When writing tests, developers often use:

    @Test
    @Transactional

to make sure that the database is cleared after each test, this is great but has a major drawback. Sometimes you want to test a transactional function that might rollback in some service:

    @Test
    @Transactional
    void checkRollbackIfFails() throws Exception {
        Mockito.doThrow(Exception.class).when(myService).sendInvoiceRequest(any(Document.class));

        int databaseSizeBeforeTest = documentReminderRepository.findAll().size();

        em.merge(documentReminder.getDocument().type(DocumentType.MEDIDATA));
        DocumentReminderDTO documentReminderDTO = documentReminderMapper.toDto(documentReminder);

         .perform(
                post(ENTITY_API_URL).content(documentReminderDTO)
            ).andExpect(status().is5xxServerError());

        List<DocumentReminder> documentReminderList = documentReminderRepository.findAll();
        assertThat(documentReminderList).hasSize(databaseSizeBeforeTest);
    }

Being in the same transaction prevents from knowing if the transaction will rollback correctly, so a fix to this would be to send the request in a nested transaction and check that the nested one did rollback correctly.

    @Test
    @Transactional
    void checkRollbackIfFails() throws Exception {
        Mockito.doThrow(Exception.class).when(myService).sendInvoiceRequest(any(Document.class));

        int databaseSizeBeforeTest = documentReminderRepository.findAll().size();

        em.merge(documentReminder.getDocument().type(DocumentType.MEDIDATA));
        DocumentReminderDTO documentReminderDTO = documentReminderMapper.toDto(documentReminder);

        this.sendCreateRequestInNewTransaction(documentReminderDTO).andExpect(status().is5xxServerError());

        List<DocumentReminder> documentReminderList = documentReminderRepository.findAll();
        assertThat(documentReminderList).hasSize(databaseSizeBeforeTest);
    }



    @Transactional(propagation = Propagation.NESTED)
    protected ResultActions sendRequestInNewTransaction(DocumentReminderDTO documentReminderDTO) throws Exception {
        return restDocumentReminderMockMvc
            .perform(
                post(ENTITY_API_URL).content(documentReminderDTO)
            );
    }

For some reason this doesn't work either we can see the reminder created by sending the request event after the nested transaction is supposed to rolled back.

Better context for understanding the logic of the code: When calling the ENTITY_API_URL a reminder is saved to the db and its new id is used to send a request to a remote server, if sending the requesting to the remote server fails, the reminder should be deleted like nothing ever happened. I would like to test that the rollback if anything bad happens. repository.delete can be used to delete instead of rollingback but I should be forced to change a good logic to make my tests work.

Comment From: snicoll

For that sort of things you should use programmatic demarcation with TransactionTemplate. The annotation model is not best suited to provide this fine grained demarcation.