7

I am using an abstract class like this:

@SpringBootTest(classes = MyAppApplication.class, webEnvironment = WebEnvironment.RANDOM_PORT)
@ActiveProfiles("test")
public abstract class AbstractIntegrationTest {

    static {
        PostgreSQLContainer postgreSQLContainer = new PostgreSQLContainer().withPassword("password")
                .withUsername("postgres").withDatabaseName("MyApp");
        postgreSQLContainer.start();

        System.setProperty("spring.datasource.url", postgreSQLContainer.getJdbcUrl());
        System.setProperty("spring.datasource.password", postgreSQLContainer.getPassword());
        System.setProperty("spring.datasource.username", postgreSQLContainer.getUsername());

    }

Then I have many tests that leverage that use that class like this:

public class moreTests extends AbstractIntegrationTest {

    TestRestTemplate restTemplate = new TestRestTemplate("my-user", "password"); 
    HttpHeaders headers = new HttpHeaders();

    @Test
    public void SimpleHealthCheck() {    
        HttpEntity<String> entity = new HttpEntity<String>(null, headers);    
        ResponseEntity<String> response = restTemplate.exchange(
                createURLWithPort("/api/v1/healthcheck"),
                HttpMethod.GET, entity, String.class);    
        assertThat(response.getStatusCode(), equalTo(HttpStatus.OK));
    }

    @Test
    public void GetInst() {    
        HttpEntity<String> entity = new HttpEntity<String>(null, headers);    
        ResponseEntity<String> response = restTemplate.exchange(
                createURLWithPort("/api/v1/institutions"),
                HttpMethod.GET, entity, String.class);
        assertThat(response.getStatusCode(), equalTo(HttpStatus.OK));    
    }

However, some of my tests will pollute the database. I'd like to control if a test runs with a fresh database or not. What's the prescribed way to do this?

user952342
  • 2,602
  • 7
  • 34
  • 54

2 Answers2

7

After more reading about Spring boot integration testing, it appears the prescribed way is to use the "@DirtiesContext" annotation for tests that are destructive (or dirty).

EDIT: After a few months, I realized @DirtiesContext is not awesome. It basically resets the whole app which can be expensive. Also, @DirtiesContext May not reset your database in some cases depending on how your app works. I suggest having a cleanup SQL script that runs in your @BeforeAll or @AfterAll section of each test class. This cleanup SQL script needs to be carefully written.

user952342
  • 2,602
  • 7
  • 34
  • 54
  • 1
    `AbstractIntegrationTest` runs Postgres in the static initialization block, this database instance will be single for all your test suite, the using of `DirtiesContext` doesn't give you a clean database after drops the spring context in a cache. In this case, you need to make some self-preparation to clean the wrong data in postgres. – Anatoliy Korovin Jun 08 '19 at 02:15
  • 1
    Good point. With our spring boot app, during startup, there is a script to cleanup the database as part of the startup.... so yeah, this might not work for everyone. Others may want to cleanup their database after a destructive test with an annotation like: @Sql(scripts={"classpath:CleanUpDatabase.sql"}) – user952342 Jun 10 '19 at 13:43
1

you either use the @Before annotation to clean everything before executing your tests.

Or you clean in each test before you execute.

Each test should be independent from the other. So usually:

  • clear and set up expectations
  • run test

If test fails, your database will be in the failed state so you can check what happened.

Toerktumlare
  • 12,548
  • 3
  • 35
  • 54