集成流测试 Spring 事务

Integration Flow Test Spring Transaction

我目前正在为我的 Spring 应用程序编写 Spock 集成测试。

我想使用 @Stepwise 来执行与数据库交互的测试,然后在第一个测试留下的数据之上构建下一个测试。

不幸的是,似乎每个测试方法都启动了一个新事务,从而清除了我需要构建的数据。 Rollback(false) 不会阻止这种行为,因为整个交易都被丢弃了 AFAIK。

这是一个示例,MyUserService@Repository 接口交互。

@Stepwise
@SpringBootTest
@TestPropertySource(locations = "classpath:application-test.properties")
class MyServiceImplIntegrationFlowSpec extends Specification {

  @Autowired
  @Subject
  MyUserService myUserService

  @Shared
  String userId

  void "create user"() {

    when:
    userId = myUserService.createUser()

    then:
    userId
  }

  void "change user permission"() {

    when:
    myUserService.changePermission(userId, "read")

    then:
    myUserService.fetchPermission() == "read"
  }
}

如何结合数据库操作重用以前的测试方法创建的数据,如通常使用 @Stepwise 所做的那样?

Spring测试框架默认回滚每个测试方法的数据。您可以通过将 @Commit 注释添加到每个要在数据库中保留更改的测试方法来更改此默认行为。如果整个测试套件应该将数据提交到数据库,我想你可以把 @Commit 注释也放在 class 级别。

见参考文献https://docs.spring.io/spring/docs/current/spring-framework-reference/testing.html#testing-tx

它说:

One common issue in tests that access a real database is their effect on the state of the persistence store. Even when you use a development database, changes to the state may affect future tests. Also, many operations — such as inserting or modifying persistent data — cannot be performed (or verified) outside of a transaction.

并继续用

描述

The TestContext framework addresses this issue. By default, the framework creates and rolls back a transaction for each test. You can write code that can assume the existence of a transaction. If you call transactionally proxied objects in your tests, they behave correctly, according to their configured transactional semantics. In addition, if a test method deletes the contents of selected tables while running within the transaction managed for the test, the transaction rolls back by default, and the database returns to its state prior to execution of the test. Transactional support is provided to a test by using a PlatformTransactionManager bean defined in the test’s application context.

If you want a transaction to commit (unusual, but occasionally useful when you want a particular test to populate or modify the database), you can tell the TestContext framework to cause the transaction to commit instead of roll back by using the @Commit annotation.

您的测试用例可能看起来像

@Stepwise
@SpringBootTest
@TestPropertySource(locations = "classpath:application-test.properties")
@Commit // if you want all test methods to commit to the database
class MyServiceImplIntegrationFlowSpec extends Specification {

  @Autowired
  @Subject
  MyUserService myUserService

  @Shared
  String userId

  @Commit // if a single test needs to commit to the database
  void "create user"() {

    when:
    userId = myUserService.createUser()

    then:
    userId
  }

  void "change user permission"() {

    when:
    myUserService.changePermission(userId, "read")

    then:
    myUserService.fetchPermission() == "read"
  }
}