Home > Blockchain >  How do I prevent data conflicts in integration test using JUnit, Spring Boot and TestContainers?
How do I prevent data conflicts in integration test using JUnit, Spring Boot and TestContainers?

Time:11-18

I'm Using Junit in Spring Boot, along with TestContainers (Docker, MySQL 8.0.29) to develop integration tests.

When I execute my tests individually, they all succeed. However when I run them all at once (i.e. in CI/CD), they fail. This is because the tests are not executed in order, and an item might already be deleted before the test to find the item is executed.

To fix this I want to give the entities a unique ID. However, the ID is already automaticly set in my Hibernate entity:

@Entity
public class Assignment {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;

I've tried to delete all items before each test is executed, however this does not work:

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @BeforeEach
    void tearDown() {
        JdbcTestUtils.deleteFromTables(jdbcTemplate, "assignment");
    }

Example integration test:

    @Test
    void When_getById_Verify_Fields() {
        AssignmentDTO assignmentDTO = new AssignmentDTO();
        assignmentDTO.setTitle("test");
        assignmentDTO.setDescription("test");
        assignmentDTO.setUserId("1");
        assignmentDTO.setCreator("1");

        assignmentService.addAssignment(assignmentDTO);

        AssignmentDTO expectedAssignment = assignmentService.getById(1);

        assertEquals(assignmentDTO.getTitle(), expectedAssignment.getTitle());
        assertEquals(assignmentDTO.getDescription(), expectedAssignment.getDescription());
        assertEquals(assignmentDTO.getUserId(), expectedAssignment.getUserId());
        assertEquals(assignmentDTO.getCreator(), expectedAssignment.getCreator());
    }

CodePudding user response:

Each test method should generally remove the data it creates to prevent this problem.

What you can do that the data is not committed to the database you can add the @Transactional annotation to the test method or the test class if you want it for all test methods.. This will do a rollback after the test method.

CodePudding user response:

if you want to execute SQL script before ou after each test you can use annotations from org.springframework.test.context.jdbc.

And an example of how to use it in a test :

@SqlGroup({
        @Sql(executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD, scripts = {
                "classpath:datasets/integration/integration_test_before.sql"}),
        @Sql(executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD, scripts = {
                "classpath:datasets/integration/integration_test_after.sql"})})

This annotations need to be adds in the class test. With this annotation you will execute a script before the test and after to initialize data and delete data.

The SQL files need to be in src/test/resources/datasets/integration.

You can find the link of a guide to use it : https://www.baeldung.com/spring-boot-data-sql-and-schema-sql

  • Related