如何测试 Spring 笔交易
How to test Spring transactions
我正在使用 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 修改的回滚。
我该怎么做?
谢谢
您可以更改方法来测试事务注释。
@Transactional
public void update() {
activityRepository.updateBacklogStatusAge();
activityRepository.updateNextStatusAge();
throw Exception();
activityRepository.updateInProgressStatusAge();
}
这将模拟您想要的场景。
您可以使用 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
}
我正在使用 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 修改的回滚。
我该怎么做? 谢谢
您可以更改方法来测试事务注释。
@Transactional
public void update() {
activityRepository.updateBacklogStatusAge();
activityRepository.updateNextStatusAge();
throw Exception();
activityRepository.updateInProgressStatusAge();
}
这将模拟您想要的场景。
您可以使用 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
}