Dherik
Dherik

Reputation: 19130

Reset database after each test on Spring without using DirtiesContext

I would like to know if there is some way to reset the database after each integration test without @DirtiesContext:

@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)

This works but it is very slow, because the Spring context is reloaded each test.

My tests are using MockMvc, doing rest calls for an API. Like:

mockMvc.perform(put("/products/)
            .header("Content-Type", "application/json")
            .content(jsonPost))
            .andExpect(status().isOk())
            .andReturn();

So, without manual intervention (create and maintain a script to drop and create the tables), the Spring framework offer some alternative?

Upvotes: 6

Views: 2953

Answers (4)

Richard
Richard

Reputation: 140

You could use org.springframework.test.context.jdbc @Sql({"clear-database.sql"}) and then just write a script to clear the db.

So you'd end up with something like this:

@Test
@Sql({"classpath:sql/clear-database.sql", "classpath:sql/set-up-db.sql"}
void doThings(){
  this.mockMvc.perform(etc..);
}

Upvotes: 0

Julian Espinel
Julian Espinel

Reputation: 3532

You can clean the tables you need by doing the following:

  1. Inject a JdbcTemplate instance
@Autowired
private JdbcTemplate jdbcTemplate;
  1. Use the class JdbcTestUtils to delete the records from the tables you need to.
JdbcTestUtils.deleteFromTables(jdbcTemplate, "table1", "table2", "table3");
  1. Call this line in the method annotated with @After or @AfterEach in your test class:
@AfterEach
void tearDown() throws DatabaseException {
    JdbcTestUtils.deleteFromTables(jdbcTemplate, "table1", "table2", "table3");
}

I found this approach in this blog post: Easy Integration Testing With Testcontainers

Upvotes: 4

Hans Runehov
Hans Runehov

Reputation: 1

I am a bit late to the party, but I had the same problem. All the unit tests (which could be considered integration tests) in an application I inherited took approximately 35 minutes to complete, using an embedded H2 as database for tests. All test classes where annotated by @DirtiesContext, usually method level.

So, the database was destroyed and recreated for each method. This takes time. By removing the dirties annotation and using a database truncation class in the @Before method I now run the complete test suite in about 4 minutes. If you have anything else than JPA stuff (not handled by the Entity manager) in your Spring context that should be removed between tests you have to do it explicitly.

I can share the DB truncation class if you like, but it is simply using the JPA meta model to find the tables to truncate. Truncation seems to be very efficient in H2. Exceptions for entities based on views, not tables, can be configured.

To make truncation easier, turn off refererential integrity before truncation and switch it back on when you're done.

Upvotes: 0

Lev Khruschev
Lev Khruschev

Reputation: 1785

In simple case annotate each your test class as @Transactional and transaction manager will do rollback after each @Test method. Get more information reading this.

Upvotes: 3

Related Questions