嵌套JUnit 5测试的Spring DataJpaTest事务行为

时间:2018-08-22 07:13:47

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

我正在使用带有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);
        }
    }

测试也通过了,但是将创建的记录保留在数据库中。在测试输出中,没有提及“交易”一词,因此,似乎我在第一个未嵌套的测试中免费获得的交易机制在嵌套情况下不会起作用。

有人在这种情况下有经验吗?

0 个答案:

没有答案