【问题标题】:How to test Spring transactions如何测试 Spring 事务
【发布时间】:2019-04-22 04:25:15
【问题描述】:

我正在使用 Spring Boot 2.1.0 进行项目,我遇到以下情况。

我有以下存储库

@Repository
public interface ActivityRepository extends PagingAndSortingRepository<Activity, Long> {

    @Transactional
    @Modifying
    @Query("") // Imagine a query
    void updateBacklogStatusAge();

    @Transactional
    @Modifying
    @Query("QUERY 2") // Imagine a query
    void updateNextStatusAge();

    @Transactional
    @Modifying
    @Query("QUERY 3") // Imagine a query
    void updateInProgressStatusAge();
}

以及以下组件

@Component
public class ColumnAgeJob {

    private final ActivityRepository activityRepository;

    public ColumnAgeJob(final ActivityRepository pActivityRepository) {
        activityRepository = pActivityRepository;
    }

    @Transactional
    public void update() {
        activityRepository.updateBacklogStatusAge();
        activityRepository.updateNextStatusAge();
        activityRepository.updateInProgressStatusAge();
    }
}

现在我想测试事务注释是否有效。

基本上,我的目标是检查 updateInProgressStatusAge() 调用期间引发的 runtimeException 是否会导致 updateNextStatusAge 和 updateBacklogStatusAge 修改回滚。

我该怎么做? 谢谢

【问题讨论】:

    标签: spring spring-boot spring-data-jpa spring-data spring-transactions


    【解决方案1】:

    你可以改变你的方法来测试你的事务注释。

    @Transactional
    public void update() {
        activityRepository.updateBacklogStatusAge();
        activityRepository.updateNextStatusAge();
        throw Exception();
        activityRepository.updateInProgressStatusAge();
    }
    

    这将模拟您想要的场景。

    【讨论】:

    • 我发现这种方法有两个问题。 1. Exception 不是 RuntimeException,如果没有在 rollbackFor 中指定,则不会回滚任何东西。 2. 这种方法在构建过程中是不可复现的,如果将来有一些回归我们无法检测到他
    • 任何 RuntimeException 都会触发回滚,而任何已检查的异常都不会。这意味着您可以使用未经检查的异常。我假设你只是想看看你的代码是否正常工作。如果你想编写单元测试,它有不同的方法。您可以查看这些链接:link1link2link3。这些链接中解释了要点。
    【解决方案2】:

    您可以使用 Mockito 来更改服务或存储库的行为,方法是使用 @SpyBean 或 @MockBean。

    不幸的是,@SpyBean 不适用于 JPA 存储库(https://github.com/spring-projects/spring-boot/issues/7033,此问题适用于 Spring boot 1.4.1,但我对 2.0.3.RELEASE 也有同样的问题)

    作为解决方法,您可以创建一个测试配置来手动创建您的模拟:

    @Configuration
    public class SpyRepositoryConfiguration {
    
       @Primary
       @Bean
       public ActivityRepository spyActivityRepository(final ActivityRepository real) 
          return Mockito.mock(ActivityRepository.class, AdditionalAnswers.delegatesTo(real));
       }
    }
    

    在你的测试中:

    @Autowired
    private ActivityRepository activityRepository;
    ....
    @Test
    public void testTransactional() {
        Mockito.doThrow(new ConstraintViolationException(Collections.emptySet())).when(activityRepository).updateInProgressStatusAge();
    
        activityRepository.updateBacklogStatusAge();
        activityRepository.updateNextStatusAge();
        activityRepository.updateInProgressStatusAge();
    
        // verify that rollback happens
    }
    

    【讨论】:

    • 无法在存储库 has been addressed 上使用 @SpyBean,并将与 Spring Boot 2.5.3 一起发布。
    猜你喜欢
    • 2010-11-01
    • 1970-01-01
    • 2011-07-16
    • 1970-01-01
    • 2014-11-14
    • 2015-06-19
    • 2011-10-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多