spring-bootrepository-patternjunit5testcontainerstestcontainers-junit5

How to test repository with junit5 and testcontainers?


I have a sample project in which I experiment with different technologies.

I have the following setup:

How can I test the Repository layer with testcontainer-junit5?

Example of code I have now for CompanyRepositoryTest.java:

@ExtendWith(SpringExtension.class)
@Testcontainers
public class CompanyRepositoryTest {

    @Autowired
    private CompanyRepository companyRepository;

    @Container
    public MySQLContainer mysqlContainer = new MySQLContainer()
            .withDatabaseName("foo")
            .withUsername("foo")
            .withPassword("secret");;

    
    @Test
    public void whenFindByIdExecuted_thenNullReturned()
            throws Exception {
        assertEquals(companyRepository.findById(1L), Optional.ofNullable(null));
    }

    @Test
    public void whenFindAllExecuted_thenEmptyListReturned() {
        assertEquals(companyRepository.findAll(), new ArrayList<>());
    }
}

When I add @SpringBootTest, I need to set up all the context and have some Application load context issues?

The question is, can anyone demystify what @TestContainers annotation does? What is the best practice or correct to use it while testing the Repository?


Solution

  • The JUnit 5 extension provided by the @Testcontainers annotation scans for any containers declared with the @Container annotation, and then starts and stops the those containers for your tests. Containers as static fields will be shared with all tests, and containers as instance fields will be started and stopped for every test.

    If you are using Spring Boot, the easiest way to setup testcontainers for your tests is probably to provide properties in application-test.yml. This will use the datasource JDBC URL to launch the testcontainers container. Refer to Testcontainers JDBC support for more information.

    You can also test just the repository layer by using @DataJpaTest instead of @SpringBootTest:

    @DataJpaTest
    @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
    @ActiveProfiles("test")
    class CompanyRepositoryTest { }
    

    Your application-test.yml file:

    spring:
      datasource:
        url: jdbc:tc:mysql:8.0://hostname/databasename
        driver-class-name: org.testcontainers.jdbc.ContainerDatabaseDriver
    

    In some cases you might also want to use the @TestPropertySource annotation instead:

    @DataJpaTest
    @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
    @TestPropertySource(
        properties = {
            "spring.datasource.url = jdbc:tc:mysql:8.0://hostname/test-database",
            "spring.datasource.driver-class-name = org.testcontainers.jdbc.ContainerDatabaseDriver"
        }
    )
    class CompanyRepositoryTest { }
    

    Please note that the hostname and test-database are not actually used anywhere.