【问题标题】:How do I test my DAO update method in an AbstractTransactionalJUnit4SpringContextTests test?如何在 AbstractTransactionalJUnit4SpringContextTests 测试中测试我的 DAO 更新方法?
【发布时间】:2019-07-19 03:18:03
【问题描述】:

我正在使用 Java 8、JUnit 4.12、Spring 4 和 Hibernate 5.2.12.Final。我想测试一个更新一些行的 Hibernate 方法。方法是这样的

        final CriteriaBuilder qb = m_entityManager.getCriteriaBuilder();
        final CriteriaUpdate<FailedEvent> q = qb.createCriteriaUpdate(FailedEvent.class);
        final Root<FailedEvent> root = q.from(FailedEvent.class);
        q.where(qb.and( qb.equal(root.get(FailedEvent_.objectId), objectId) ));
        q.set(root.get(FailedEvent_.flaggedForDelete), true);
        affectedRows = m_entityManager.createQuery(q).executeUpdate();
     return affectedRows > 0;

我有以下 JUnit 测试来验证这一点

public class FailedEventDaoTest extends AbstractTransactionalJUnit4SpringContextTests
...

    @Test
    public final void testFlagForDeleteByObjectId()
    {
            final String eventId = "testId";
            final FailedEvent event = failedEventDao.findByEventId(eventId);
            Assert.assertFalse("A pre-condition fo this test is that an failed_event record with id \"" + eventId + "\" have a non-empty object id.", StringUtils.isEmpty(event.getObjectId()));
            Assert.assertTrue(failedEventDao.flagForDeleteByObjectId(event.getObjectId()));
            final FailedEvent foundEvent = failedEventDao.findByEventId(eventId);
            Assert.assertTrue("Failed to mark flag for deletion.", foundEvent.getFlaggedForDelete());
    }   // testFlagForDeleteByObjectId

但是我的测试在最后一行失败了,

Assert.assertTrue("Failed to mark flag for deletion.", foundEvent.getFlaggedForDelete());

这是因为事务尚未完成,所以数据库中没有任何更新?我可以通过什么方式来验证是否更新了正确的记录?

【问题讨论】:

  • 应该是同一个事务。您可以在 Hibernate 中设置 SQL 语句记录以检查实际正在执行的 SQL
  • 我打开它并验证 SQL 语句已执行。事实上,“affectedRows = m_entityManager.createQuery ...”行表示受影响的多行,所以我认为这意味着事情已成功执行。
  • 我并不是要在你的问题中抛出扳手,但我想问一下,你为什么要对数据库操作进行单元测试?我不确定您从对数据库操作进行单元测试中获得了什么价值。从您的断言来看,您似乎没有在测试任何业务需求。大多数时候,我们只是模拟所有需要实时运行系统进行单元测试的东西。坦率地说,如果您这样做只是为了满足您的代码覆盖率要求,那么您就是在浪费时间。你的时间会花在编写测试上,这会增加更多的价值。
  • 方法foundEvent.getFlaggedForDelete()的返回值是什么?
  • 能否发送FailedEvent 类以及flagForDeleteByObjectIdfindByEventId 方法?

标签: java spring hibernate junit transactions


【解决方案1】:

您应该考虑不要扩展抽象类并使用不同的方法。 例如

@RunWith(SpringJUnit4ClassRunner.class) 
@Transactional

在课堂上。

喜欢:

  package com.example;

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;

import com.example.model.Person;
import com.example.service.PersonService;

@RunWith(SpringJUnit4ClassRunner.class)
@Transactional
@ContextConfiguration("classpath:/spring-beans.xml")
public class PersonServiceIntegrationTests {
    @Autowired
    private PersonService personService;

    @Autowired
    private JdbcTemplate jdbcTemplate;


    @Test
    public void shouldCreateNewPerson() {
        Person person = new Person();
        person.setFirstName("Kenan");
        person.setLastName("Sevindik");

        long countBeforeInsert = jdbcTemplate.queryForObject("select count(*) from t_person", Long.class);
        Assert.assertEquals(2, countBeforeInsert);

        personService.create(person);

        long countAfterInsert = jdbcTemplate.queryForObject("select count(*) from t_person", Long.class);
        Assert.assertEquals(3, countAfterInsert);
    }

    @Test
    public void shouldDeleteNewPerson() {
        long countBeforeDelete = jdbcTemplate.queryForObject("select count(*) from t_person", Long.class);
        Assert.assertEquals(2, countBeforeDelete);

        personService.delete(1L);

        long countAfterDelete = jdbcTemplate.queryForObject("select count(*) from t_person", Long.class);
        Assert.assertEquals(1, countAfterDelete);
    }

    @Test
    public void shouldFindPersonsById() {
        Person person = personService.findById(1L);

        Assert.assertNotNull(person);
        Assert.assertEquals("John", person.getFirstName());
        Assert.assertEquals("Doe", person.getLastName());
    }
}

看看https://examples.javacodegeeks.com/enterprise-java/spring/write-transactional-unit-tests-spring/#section_7

或者

  @RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration(

  classes = { StudentJpaConfig.class }, 

  loader = AnnotationConfigContextLoader.class)

@Transactional

public class InMemoryDBTest {

     

    @Resource

    private StudentRepository studentRepository;

     

    @Test

    public void givenStudent_whenSave_thenGetOk() {

        Student student = new Student(1, "john");

        studentRepository.save(student);

         

        Student student2 = studentRepository.findOne(1);

        assertEquals("john", student2.getName());

    }

}

看看这个 https://www.baeldung.com/spring-jpa-test-in-memory-database

【讨论】:

    【解决方案2】:

    尝试@AfterTransaction 注解来测试结果。

        @AfterTransaction
        public final void theRealTest()
        {
                Assert.assertTrue("Failed to mark flag for deletion.", foundEvent.getFlaggedForDelete());
        }
    

    https://www.springbyexample.org/examples/simple-spring-transactional-junit4-test-code-example.html

    如果这也不起作用,请尝试:

    “因此,您需要在测试方法中创建多个事务。 如您所见,您不能使用 AbstractTransactionalJUnit4SpringContextTests,因为它创建了一个 整个测试方法的单一事务,不能使用裸 AbstractJUnit4SpringContextTests,因为它不创建事务 完全没有。

    解决方案是使用 AbstractJUnit4SpringContextTests 并管理 以编程方式在您的测试方法中进行事务处理。

    您需要将 PlatformTransactionManager 注入到您的测试中,创建 TransactionTemplate 并使用它来划分您的交易 如 11.6 程序化事务管理中所述。”

    在这里找到: Using AbstractTransactionalJUnit4SpringContextTests with commit halfway through

    【讨论】:

    • 我在哪里将此代码添加到我的 JUnit 测试类中?
    • 是的。看看我添加的链接。只是您实际的 @Test 注释方法下的另一种方法。
    • 另外一件事——在我的测试中,“foundEvent”是该方法的本地变量,但由于您已将其放在单独的方法中,您希望我将其设为全局变量吗?这个@AfterTransaction 是否在我在该类中的每个测试之后运行(我只列出了一个测试,但它有几个)?如果是这样,是否有任何方法可以让测试本身工作而不影响所有其他测试?
    • 您应该考虑不要扩展抽象类并使用不同的方法。例如 @RunWith(SpringJUnit4ClassRunner.class) @Transactional 类上的注解。看看这个examples.javacodegeeks.com/enterprise-java/spring/…
    猜你喜欢
    • 2013-11-05
    • 2018-11-14
    • 1970-01-01
    • 1970-01-01
    • 2015-04-07
    • 1970-01-01
    • 1970-01-01
    • 2011-09-13
    • 1970-01-01
    相关资源
    最近更新 更多