6

I have some tests written for a micronaut micro service. I would want that after my tests are done all the changes in the DB are reverted (rollback). Firstly I have written a simple example which seems to work. Changes are reverted. But when I run a micro service test using the same analogy the changes are not reverted.

Simple working example:

@Test
@Transactional
public void testRollback() {
    try (Connection connection = dataSource.getConnection();

        Statement stmt = connection.createStatement()){
        connection.setAutoCommit(false);
        stmt.execute(String.format("INSERT INTO city VALUES (9999, 'Darko town', '123')"));
        connection.rollback();

    } catch (SQLException e) {
        Assert.fail("Exception " + e);
    }
}

After this is executed the city is removed from the DB.

My real test scenario:

@Test
@Transactional
public void testDeleteDocuments() {

    try (final Connection connection = deletionService.getDataSource().getConnection(); 

        Statement stmt = connection.createStatement()) {
        connection.setAutoCommit(false);
        deletionService.startHacDeletion();
        connection.rollback();

    }catch (SQLException e) {
        Assert.fail("Exception " + e);
    }

}

Everything done by the method I am testing: DeletionService.startHacDeletion() is not reverted.

Am I missing something? Is this the right approach? Please assist....

UPDATE:

here is the delete function

public void deleteHacDocuments () {

    List<Document> allComments = new ArrayList<>();

    while (hacDeletionActive) {
        List<Document> parentDocuments = documentRepository.findHacDocuments();

        LOG.info(String.format("Remove HAC parent documents %d", parentDocuments.size()));

        for(Document document : parentDocuments){
            LOG.info(String.format("Remove HAC documents %d", document.getId()));
        }


        if (parentDocuments.isEmpty()) {
            hacDeletionActive = false;
            LOG.info("HAC deletion finished");
        } else {

            for (Document doc : parentDocuments) {
                if (doc.getType() == 1) {
                     deleteWholeStudy(doc.getId());
                } else if (doc.getType() == 6) {
                    List<Document> studies = documentRepository.findStudiesByCase(doc.getId());

                    for (Document study : studies) {
                        deleteWholeStudy(study.getId());
                    }

                    deleteWholeCase(doc.getId());

                } else if (doc.getType() == 4) {
                    allComments.add(doc);
                } else {
                    documentService.markDocumentAsDeleted(doc.getId());
                }
            }
            documentService.markCommentsAsDeleted(allComments);
        }

}
}
Jacob
  • 3,580
  • 22
  • 82
  • 146

5 Answers5

0

I am not very familiar with the Micronaut framework and do not really understand why the @Transactional annotation is needed if you roll back the changes manually.

But what is obvious from your examples, that in the first case, you use a connection to create an statement which is used to execute a query, and then you call rollback on the same connection. In the second case, you get a connection from the DataSource, but you do not pass it to the service to use it, therefore if DataSource uses some connection pool and does not always return the same connection, the service will obtain another connection from it, not the one you are rolling back.

This is the only possible issue I can see in your code, if my answer does not help solve your problem, please provide a minimal, reproducible example.

Anar Sultanov
  • 3,016
  • 2
  • 17
  • 27
0

Dbunit is a special extension for JUnit for database testing http://dbunit.sourceforge.net/howto.html

JUnit itself isn't designed to work with a database, thus, you faced this problem and thinking on a complex solution.

lazylead
  • 1,453
  • 1
  • 14
  • 26
0

Not exactly the same use case because I use Spock for testing but I'm pretty sure that something like the following exists in JUnit.

What I do in every test that writes some data in the database is executing a cleanup block that deletes all the data created. To make sure that we don't forget to delete everything created in the test and we pollute other tests, we have a parent cleanup that it's executed after every test and makes sure that there is no data in the database. Basically run select count(*) from xxxxx and if there is data there the test fails.

As mentioned before, it's not a real answer for your question but a different approach that you could follow. It's working really well for us.

Iván López
  • 944
  • 4
  • 13
0

Depending on which testing library your using you need to setUp and tearDown the test data. Inject the Datasource into the Test class and use datasource.connection to execute queries to clean up the data.

Swanand Keskar
  • 1,023
  • 1
  • 13
  • 27
0

Annotate your rest class with @MicronautTest and it will do the rollback by default. Get rid of all the try/catch connection stuff you're doing. You shouldn't need to explicitly rollback your connection. See an example here: https://github.com/micronaut-projects/micronaut-test/blob/master/test-junit5/src/test/java/io/micronaut/test/junit5/JpaRollbackTest.java

neildo
  • 2,206
  • 15
  • 12