How to cleanup h2 db after each junit test?

Viewed 2315

I am making junit tests which adds some users before each test case. The code is:

@BeforeEach
    void setUp() {
        saveUser();
        saveEntry();
    }
    
    @Test
    void saveUser() {
        User user = new User();
        user.setUserId(null);
        user.setUsername("John");
        user.setEmail("john@foo.com");
        user.setPassword("password");
        userService.saveUser(user);
    }

    @Test
    void saveEntry() {
        Entry entry = new Entry();
        entry.setText("test text");
        entry.setUserId(1L);
        entryService.saveEntry(entry);
    }

As you see I am using the methods that I have in my service layer to create entries and users. If I run the tests one by one there is no problem. But when I run all tests then db is not returning 1 item and returning multiple items so exception occurs.

I need to cleanup h2 db after each test with maybe @AfterEach annotation but I do not have and delete method in my code to invoke. How can I cleanup the H2 db ?

3 Answers

In addition to @J Asgarov answer which is correct providing you use spring-boot if you want to perform some actions before and after each test (more specifically before @Before and after @After methods) you can use @Sql annotation to execute specific sql script for example from test resources.

@Sql("init.sql")
@Sql(scripts = "clean.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD)
public class TestClass
}

It might be handy for sequences, since they don't care of rollback.

Regarding @Transactional mentioned by @Mark Bramnik be careful, because the transaction spans for entire test method, so you cannot verify correctness of the transaction boundaries.

You've mentioned spring and it looks like you're testing DAO layer, so I assume the tests are running with SpringExtension/SpringRunner if you're on junit 4.

In this case,

Have you tried to use @Transactional on the test method? Or alternatively if all the test methods are "transactional" you can place it once on a test class.

This works as follows:

If everything is configured correctly spring will open a transaction before the test starts, and will rollback that transaction after the test ends.

The rollback is supposed to clean the inserted data automatically.

Quick googling revealed this tutorial, surely there are many others

Related