在集成测试中每个方法不回滚后 Spring Data JPA 数据库更改

Posted

技术标签:

【中文标题】在集成测试中每个方法不回滚后 Spring Data JPA 数据库更改【英文标题】:Spring Data JPA database changes after each method don't roll back in integration tests 【发布时间】:2020-08-08 19:01:26 【问题描述】:

我正在使用 JUnit 5Spring boot 2.2.4 来集成测试我的 Spring Boot 应用程序代码与 MySQL 5.7 数据库,但 strong>以前的测试方法对数据库所做的更改不会回滚,这会导致后面的错误。

我尝试了来自不同 *** 帖子的答案,例如添加 @Transactional(来自 Spring)、@Rollback(方法和类级别)、@TestExecutionListeners(listeners = TransactionalTestExecutionListener.class)。我已经单独(以及组合)测试了这些选项,但将它们一起添加到测试代码中。

这是我的测试代码:

@DataJpaTest
@Transactional
@Rollback
@ExtendWith(SpringExtension.class)
@Import(UserUsecasesImpl.class)
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
class UserUsecasesImplINTTest 

    @Autowired
    private TestEntityManager entityManager;
    @Autowired
    @Spy
    private UserRepository userRepository;
    @Autowired
    private UserUsecases userUsecases;

    @Test
    void injectedComponentsAreNotNull()
        assertNotNull(entityManager);
        assertNotNull(userRepository);
        assertNotNull(userUsecases);
    

    @Test
    @Rollback
    void Create_EntityAlreadyExists_ReturnsException() 
        // set up
        User expected = UserFixture.user1.toBuilder().build();
        // entityManager.persistAndFlush(expected);
        userRepository.saveAndFlush(expected);

        // execute
        User actual = userUsecases.create(expected);

        // verify
        assertEquals(expected, actual);
        verify(userRepository).findOne(any(Example.class));
        verify(userRepository, never()).save(any(User.class));
        verifyNoMoreInteractions();
    

    @Test
    void Find_WhenUserPresent_ReturnUser() 
        // // set up
        User expected = UserFixture.user1.toBuilder().build();
        entityManager.persistAndFlush(expected);

        // execute
        User actual = userRepository.find(expected);

        // verify
        assertEquals(expected, actual);
    

    @Test
    // @Transactional
    void Find_WhenUserNotPresent_ReturnNull() 
        // // set up
        User expected = UserFixture.user1.toBuilder().build();
        // entityManager.persistAndFlush(UserFixture.user2.toBuilder().build());

        // execute
        User actual = userUsecases.find(expected);

        // verify
        assertNull(actual);
    

UserUsecasesImpl 是我要测试的类,其中包含创建用户、查找用户、获取所有用户等用例。代码中的其他任何地方都没有特殊配置。

【问题讨论】:

好的,请把所有类重命名为正常的命名约定,我看不懂。让Repository调用类实现JPA存储库,不要调用POJO'DAO'和Datasource??我读到这里就得强迫症了。 好的。给您带来的不便,我们深表歉意。 @JAsgarov 提到的类名没有意义。请将此更改为正确的命名,否则将无法阅读。第二件事,为什么要对您的实际数据库进行集成测试。在类路径中使用 h2,范围为测试或 testRuntimeOnly。在您的资源中定义适当的 application-test.yml。声明测试属性源并使用它。我看到许多注释没有用,因为 DataJpaTest 本身就是您使用的大多数注释的元注释。 我已经更新了类名。 @Priyak Dey 最初我使用的是 h2,但我想确保数据库中发生了什么,我能想到的最简单的方法是使用 mysql,以便我可以连接到它并查看断点处发生的情况。我定义了一个由 spring.profiles.active="test" 激活的附加 application-test.properties。 这不是一个解决方案,但我能够让测试用例为我工作。我从 MySQL 切换到 H2,然后在每个测试方法之后回滚。 【参考方案1】:

请实施以下修复,如果问题仍然存在,请告诉我:

    删除所有@Transactional@Rollback。保留@DataJpaTest,默认情况下,这会使您的所有测试@Transactional,因此默认情况下会将它们全部回滚。 不要使用saveAndFlush。刷新部分是将保存操作刷新到数据库中,很可能会导致您的问题。请改用save。更多在这里https://www.baeldung.com/spring-data-jpa-save-saveandflush 如果您期望出现异常,请使用 assertThrows 断言它。

一般来说,尽量不要同时将你知道的每一个注释都扔到混合中。根据需要一次添加一个,尝试了解它们的作用。

什么是 UserUseCases,为什么它会执行我希望 Repository 类执行的大部分逻辑?

【讨论】:

我尝试了您推荐的建议,尤其是第二条但没有解决问题(刷新并不意味着提交***.com/questions/14581865/hibernate-flush-and-commit)。 Spring Data(或休眠)是否不依赖于数据库的本机事务,如果是这种情况,即使它已将数据推送到数据库,它也应该能够回滚。我实际上是从 Flutter 搬到 Spring 的,在那里我会遵循这个结构 resocoder.com/2019/08/27/…。 TL;DR 用例可能与超过 1 个存储库交互。

以上是关于在集成测试中每个方法不回滚后 Spring Data JPA 数据库更改的主要内容,如果未能解决你的问题,请参考以下文章

Spring/JTA/JPA DAO 集成测试不回滚?

弹簧测试在测试后不回滚

Spring boot,测试后事务不回滚

Spring @Transactional注解不回滚不起作用无效

由于异常回滚后的Spring批量更新数据库状态

@Transaction不回滚事务问题