Gavi
Gavi

Reputation: 1488

How to test Spring transactions

I'm working to a project with Spring Boot 2.1.0 and I've the following situation.

I've the following repository

@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();
}

and the following component

@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();
    }
}

Now I want to test if the transactional annotation is working.

Basically my goal is to check if a runtimeException raised during the updateInProgressStatusAge() call will cause a rollback of updateNextStatusAge and updateBacklogStatusAge modifications.

How can I do that? Thank you

Upvotes: 3

Views: 6663

Answers (2)

ccardone
ccardone

Reputation: 76

You can use Mockito in order to change the behaviour of your service or repository by using @SpyBean or @MockBean.

Unfortunately @SpyBean do not works on JPA repository (https://github.com/spring-projects/spring-boot/issues/7033, this issue is for Spring boot 1.4.1, but I have the same problem with 2.0.3.RELEASE)

As workaround you can create a test configuration to create manually your mock:

@Configuration
public class SpyRepositoryConfiguration {

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

And in your test:

@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
}

Upvotes: 5

uğur taş
uğur taş

Reputation: 365

You can change your method to test your transactional annotation.

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

This will simulate your desired scenario.

Upvotes: 0

Related Questions