Search code examples
javaspring-transactionsspring-test

@Transactional annotation in Spring Test


I am reading Spring docs about Spring test in: here

And about using @Transactinoal on tests it says:

If your test is @Transactional, it rolls back the transaction at the end of each test method by default. However, as using this arrangement with either RANDOM_PORT or DEFINED_PORT implicitly provides a real servlet environment, the HTTP client and server run in separate threads and, thus, in separate transactions. Any transaction initiated on the server does not roll back in this case.

I do not understand what does it exactly means by Any transaction initiated on the server does not roll back in this case.

Any help is appreciated.


Solution

  • It means that your server won't rollback your changes because it will run in another environment than the test environment. Only changes you have made in your test environment would be rollbacked.

    For instance:

    @Autowired
    private AnyRepository anyRepository;
    
    @Test
    @Transactional
    void testSave(){
      anyRepository.save(new AnyEntity());
      // Will create an entity from your test environment
    }
    
    @Test
    @Transactional
    void testRead(){
      anyRepository.findAll();
      // Won't find any entities since they were rollbacked
    }
    

    On the contrary, if you launched a local instance of Spring using @SpringBootTest(webEnvironment = WebEnvironment.DEFINED_PORT) for instance), it is detached from your unit test environment, hence:

    @Autowired
    MockMvc mvc;
    
    @Test
    @Transactional
    void testSave(){
      mvc.perform(post(/* enough to create an entity */);
      // Your server, detached from test environment, persists the entity
    }
    
    @Test
    @Transactional
    void testRead(){
      mvc.perform(get(/* enough to get that entity */);
      // Will get previously created entity (if testSave was run before)
    }
    

    If you want to rollback after sending a web request, you could use the @DirtiesContext annotation to reset your context, or check Reset database after each test on Spring without using DirtiesContext.

    edit: following comments on original post, it was not clear whether you needed to use WebEnvironment.RANDOM_PORT or if it was a simple question.
    Most likely, if you do not need WebEnvironment.RANDOM_PORT, you can simply use WebEnvironment.MOCK, which runs in the same environment that the JUnit tests, hence would actually rollback.