【问题标题】:How to reset between tests如何在测试之间重置
【发布时间】:2017-04-26 20:07:39
【问题描述】:

我有一个测试类

@RunWith(SpringRunner.class)
@DataJpaTest

我有两个测试。在每次测试中,我都会执行相同的操作,持久化对象。只有 find 调用不同。

如果我同时运行两个测试,它们会失败,但如果我一个接一个地运行测试,它们就会成功。

每次测试之间没有重置。怎么做?在每个测试中,只有对存储库的调用不同。

@Test
public void findTopByCommerceCommerceIdOrderByEntryTimeDesc() {

    Long commerceId = 1L;

    Commerce commerce = new Commerce();
    commerce.setName("test");
    this.entityManager.persist(commerce);

    Member member = new Member();
    member.setCommerce(commerce);
    member.setMan(true);
    member.setName("bob binette");

    this.entityManager.persist(member);

    Visit visit1 = new Visit();
    visit1.setCommerce(commerce);

    visit1.setMember(member);
    visit1.setEntryTime(LocalDateTime.of(LocalDate.now(), LocalTime.now()));

    Visit visit2 = new Visit();
    visit2.setCommerce(commerce);

    visit2.setMember(member);
    visit2.setEntryTime(LocalDateTime.of(LocalDate.now().minusDays(2), LocalTime.now()));

    this.entityManager.persist(visit1);
    this.entityManager.persist(visit2);

    Visit visit = visitRepository.findTopByCommerceCommerceIdOrderByEntryTimeDesc(commerceId);

    assertEquals(visit.getVisitId(), Long.valueOf("1"));

}

编辑

我把所有的代码:http://pastebin.com/M9w9hEYQ

【问题讨论】:

标签: java spring spring-boot spring-data-jpa junit4


【解决方案1】:

添加@DirtiesContext 注释,但为其提供AFTER_EACH_TEST_METHOD classMode

@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)

【讨论】:

  • 感谢@HPacquee。即使是很久以前,也拯救了我的一天。 :)
  • 如果你想要一个快速的反馈循环,不要使用@DirtiesContext!它可以工作,但会大大减慢您的测试速度。这是最糟糕的选择。
【解决方案2】:

在您的每个测试中,您都保留相同的数据。因此,您应该在所有测试之前持久化数据,或者在每次测试之前持久化并在之后清理。

1.在所有测试之前坚持下去

@BeforeClass
public static void init(){
  //persist your data
}

@AfterClass
public static void clear(){
  //remove your data
}

@Test
public void findTopByCommerceCommerceIdOrderByEntryTimeDesc() {
    Visit visit = visitRepository.findTopByCommerceCommerceIdOrderByEntryTimeDesc(commerceId);

    assertEquals(visit.getVisitId(), Long.valueOf("1"));
}

在这种情况下@AfterClass 是可选的

2。每次测试前坚持,每次测试后清理

    @Before
    public void init(){
      //persist your data
    }

    @After
    public void clear(){
      //remove your data
    }

    @Test
    public void findTopByCommerceCommerceIdOrderByEntryTimeDesc() {
        Visit visit = visitRepository.findTopByCommerceCommerceIdOrderByEntryTimeDesc(commerceId);

        assertEquals(visit.getVisitId(), Long.valueOf("1"));
    }

记住使用@BeforeClass 和@AfterClass 的方法必须是静态的。

【讨论】:

  • 我建议@Before@After。推荐做法:stackoverflow.com/a/14737697/5012277
  • 试图添加 this.entityManager.remove(visit1); this.entityManager.remove(visit2);在断言之后......得到同样的问题
  • 你能添加sn-p吗?
【解决方案3】:

您可以在测试类上使用@DirtiesContext 注释来重置测试,您还可以选择何时重置。默认在每个方法之后,但您可以通过将不同的参数传递给 @DirtiesContext 注释来更改它。

import org.springframework.test.annotation.DirtiesContext;

@RunWith(SpringRunner.class)
@DataJpaTest
@DirtiesContext
public class VisitRepositoryTest {

【讨论】:

  • 在每个保留一个实体的方法可以将自动递增的 ID(在我的例子中是 Postgresql 序列)重置回 1 之前添加它。Brilliant Spring。
【解决方案4】:

将@Sql 与 ExecutionPhase.AFTER_TEST_METHOD 一起使用并传递用于清理数据库的脚本

@Sql(scripts="classpath:cleanup.sql",executionPhase=Sql.ExecutionPhase.AFTER_TEST_METHOD)
@Test
public void whateverIsYourTestMethod()
{
...
}

如果你使用@Transactional注解,你可以使用:

@Sql(scripts="classpath:cleanup.sql",executionPhase=Sql.ExecutionPhase.AFTER_TEST_METHOD,config = @SqlConfig
        ( transactionMode = TransactionMode.ISOLATED,
        transactionManager = "transactionManager",
        dataSource= "dataSource" ))
@Test
@Commit
@Transactional
public void whateverIsYourTestMethod(){...}

【讨论】:

    【解决方案5】:

    您是否尝试清除每个测试之间的持久性缓存,根据 TestEntityManager#clear()

    @After
    public void clear() {
        this.entityManager.clear();
    }
    

    或者尝试将您的 Visitor 设置为字段并在之后删除它们,而不是刷新更改:

    Visit visit1;
    
    Visit visit2;
    
    @After
    public void clear(){
      if (visit1 != null)
          this.entityManager.remove(visit1);
      if (visit2 != null)
          this.entityManager.remove(visit2);
      this.entityManager.flush();
    }
    

    【讨论】:

      【解决方案6】:

      @DirtiesContext(classMode =DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD) 对我有用,但只有当我运行 @DataJpaTest()@AutoConfigureTestDatabase(replace=Replace.NONE) 和 mysql 的 costum 配置文件时才有必要,默认 h2 没有这个工作。

      【讨论】:

        【解决方案7】:

        在您的测试类顶部使用@Transactional(propagation = Propagation.REQUIRES_NEW),它将显式请求在每个方法之后创建一个新事务

        【讨论】:

          【解决方案8】:

          虽然这个问题已经为您解决了,但我只想声明清除存储库并没有针对我的特定用例进行切割,因为我的 h2 有一个 data.sql 初始化,默认情况下会创建一个用户,所以我必须在 src/test/resources 下添加一个 application.properties 文件,该文件具有以下属性:

          spring.datasource.initialization-mode=never

          参考提出该建议的线程: Spring Boot ignore data.sql when running unit tests

          【讨论】:

            猜你喜欢
            • 2022-01-04
            • 1970-01-01
            • 2018-07-26
            • 2015-03-16
            • 1970-01-01
            • 2018-08-05
            • 2012-06-03
            • 2015-07-01
            • 1970-01-01
            相关资源
            最近更新 更多