我正在使用带有JUnit 5的Spring Boot 2,为JpaRepository编写DataJpaTest。这些测试是针对真实的PostgreSQL数据库(不是嵌入式数据库,不是内存数据库)运行。
根据文档,默认情况下,每个测试都在事务中,并且会自动回滚。确实,这就是我无需付出任何额外努力即可获得的行为。这是我的测试最初的样子:
@ExtendWith(SpringExtension.class)
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@DataJpaTest
class MyRepositoryIT {
@Autowired
private TestEntityManager entityManager;
@Autowired
private MyRepository myRepository;
@Test
void save() {
// arrange
MyEntity entity = new MyEntity().withName("Nikolaos");
// act
MyEntity saved = myRepository.save(entity);
// assert
assertThat(saved.getId()).isGreaterThan(0);
}
这按预期工作,实际上在测试输出中,我可以看到它正在回滚事务:
20180822T085911 main INFO c.u.m.a.d.MyRepositoryIT Started MyRepositoryIT in 8.352 seconds (JVM running for 10.726)
20180822T085911 main INFO o.s.t.c.t.TransactionContext Began transaction (1) for test context [DefaultTestContext@1a8e9ed9 testClass = MyRepositoryIT, testInstance = acme.auth.db.MyRepositoryIT@68ea253b, testMethod = save@MyRepositoryIT, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@12fcb2c3 testClass = MyRepositoryIT, locations = '{}', classes = '{class acme.auth.Swagger2SpringBoot}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true}', contextCustomizers = set[[ImportsContextCustomizer@57bd6a8f key = [org.springframework.boot.test.autoconfigure.jdbc.TestDatabaseAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration, org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration, org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration, org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration, org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration, org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration, org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManagerAutoConfiguration]], org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@57d5872c, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@6ee12bac, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.autoconfigure.OverrideAutoConfigurationContextCustomizerFactory$DisableAutoConfigurationContextCustomizer@1b083826, org.springframework.boot.test.autoconfigure.filter.TypeExcludeFiltersContextCustomizer@351584c0, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@3dc05093, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@2d9d4f9d], contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map[[empty]]]; transaction manager [org.springframework.orm.jpa.JpaTransactionManager@6a6c7f42]; rollback [true]
Hibernate: insert into MyTable (firstname) values (?)
20180822T085912 main INFO o.h.h.i.QueryTranslatorFactoryInitiator HHH000397: Using ASTQueryTranslatorFactory
Hibernate: select My0_.id as id1_4_, My0_.firstname as firstname2_4_ from My My0_
20180822T085912 main INFO o.s.t.c.t.TransactionContext Rolled back transaction for test: [DefaultTestContext@1a8e9ed9 testClass = MyRepositoryIT, testInstance = acme.auth.db.MyRepositoryIT@68ea253b, testMethod = save@MyRepositoryIT, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@12fcb2c3 testClass = MyRepositoryIT, locations = '{}', classes = '{class acme.auth.Swagger2SpringBoot}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true}', contextCustomizers = set[[ImportsContextCustomizer@57bd6a8f key = [org.springframework.boot.test.autoconfigure.jdbc.TestDatabaseAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration, org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration, org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration, org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration, org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration, org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration, org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManagerAutoConfiguration]], org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@57d5872c, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@6ee12bac, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.autoconfigure.OverrideAutoConfigurationContextCustomizerFactory$DisableAutoConfigurationContextCustomizer@1b083826, org.springframework.boot.test.autoconfigure.filter.TypeExcludeFiltersContextCustomizer@351584c0, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@3dc05093, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@2d9d4f9d], contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map[[empty]]]
并且实际上在数据库中,该表没有测试中的任何剩余记录。
但是,我想使用JUnit 5嵌套测试,以便可以构造测试先决条件。
当我这样更改测试时,它不再回滚事务,并且数据库被污染:
@ExtendWith(SpringExtension.class)
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@DataJpaTest
class MyRepositoryIT {
@Autowired
private TestEntityManager entityManager;
@Autowired
private MyRepository myRepository;
@Nested
class WhenTableIsEmpty {
@Test
void save() {
// arrange
MyEntity entity = new MyEntity().withName("Nikolaos");
// act
MyEntity saved = myRepository.save(entity);
// assert
assertThat(saved.getId()).isGreaterThan(0);
}
}
测试也通过了,但是将创建的记录保留在数据库中。在测试输出中,没有提及“交易”一词,因此,似乎我在第一个未嵌套的测试中免费获得的交易机制在嵌套情况下不会起作用。
有人在这种情况下有经验吗?