dimanche 10 janvier 2021

H2 integration tests: dropping tables between tests does not work

I'll do my best to keep it very minimal.

This is the /scripts/exercises.sql file:

INSERT INTO exercises (id, name, description, difficulty) VALUES (10, 'Exercise 1', 'Description 1', 1);
INSERT INTO exercises (id, name, description, difficulty) VALUES (20, 'Exercise 2', 'Description 2', 2);

And the actual integration test:

@Sql(scripts = "/scripts/exercises.sql")
public class ExerciseIntegrationTest extends IntegrationTestSetup {

  /** This test passes. */
  @Test
  public void getAll() {
    client() // this comes from the base class
        .when()
        .get("/exercises")
        .then()
        .statusCode(200)
        .body("size()", equalTo(2));
  }

  /** This test fails due to the primary key collision exception. */
  /** This test could have even an empty body. */
  @Test
  public void getOne() {
    client()
        .when()
        .get("/exercises/10")
        .then()
        .statusCode(200)
        .body("id", equalTo(10))
        .body("name", equalTo("Exercise 1"))
        .body("description", equalTo("Description 1"))
        .body("difficulty", equalTo(1));
  }

The first test passes. The second test fails, because it tries to re-create the database, however it cannot re-create the database due to JdbcSQLIntegrityConstraintViolationException: Unique index or primary key violation (Primary Key collision).

The system has problems with re-creating the database between each test.

If I ran just the second test alone, then it would pass.

If I put the @Sql on the first test only, instead of on the class, then both test would succeed.

The error:

org.springframework.jdbc.datasource.init.ScriptStatementFailedException: Failed to execute SQL script statement #1 of class path resource [scripts/exercises.sql]: INSERT INTO exercises (id, name, description, difficulty) VALUES (10, 'Exercise 1', 'Description 1', 1); nested exception is org.h2.jdbc.JdbcSQLIntegrityConstraintViolationException: Primary Key Violation (translated from non-english): "PRIMARY KEY ON PUBLIC.EXERCISES(ID) [10, 'Description 1', 1, 'Exercise 1']"
Unique index or primary key violation: "PRIMARY KEY ON PUBLIC.EXERCISES(ID) [10, 'Description 1', 1, 'Exercise 1']"; SQL statement:
INSERT INTO exercises (id, name, description, difficulty) VALUES (10, 'Exercise 1', 'Description 1', 1) [23505-200]

Here is the base class:

@ActiveProfiles("test")
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class IntegrationTestSetup {

  @LocalServerPort
  private int serverPort;

  public RequestSpecification client() {
    return RestAssured.given()
        .basePath("/api/v1")
        .port(serverPort)
        .accept(MediaType.APPLICATION_JSON.toString())
        .contentType(MediaType.APPLICATION_JSON.toString());
  }
}

And here is the application-test.yml:

spring:
  datasource:
    url: jdbc:h2:mem:test_database;DB_CLOSE_DELAY=-1
    username: sa
    password:
    driverClassName: org.h2.Driver

  profiles:
    active: test

Thanks for help.

P.S. I need to re-create the db between the tests, because the test may e.g. persist or remove entity.

Aucun commentaire:

Enregistrer un commentaire