How to test repository with junit5 and testcontainers?

六月ゝ 毕业季﹏ 提交于 2021-01-29 08:12:19

问题


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

I have the following setup:

  • Spring Boot 2.3.4.RELEASE
  • Flyway 7.0.1
  • Testcontainers 1.15.0-rc2
  • Junit 5.7.0

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?


回答1:


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.




回答2:


You said

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

If you'd like to try an alternative and Testcontainer is not mandatory you can do it differently.

You do not need to load everyting when using SpringBootTest annotation, you can specify which classes are needed such as

@SpringBootTest(classes = { TheService.class })

or use @Import annotation

and mock others such as

@MockBean
MyService service;

For database connection you can use annotation such as

@ActiveProfiles("my-profile-for-jpa-test")
@DataJpaTest
@EnableJpaAuditing
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)

EDIT: I feel like this should be an comment but I wanted to address the SpringBootTest part of the question with proper formatting




回答3:


  1. As per docs:

The test containers extension finds all fields that are annotated with Container and calls their container lifecycle methods. Containers declared as static fields will be shared between test methods. They will be started only once before any test method is executed and stopped after the last test method has executed. Containers declared as instance fields will be started and stopped for every test method.

So in your case it will recreate a container for every test method, it's only responsible for starting and stopping the container. If you need some test data - that has to be done manually, as I see you have Flyway, that should do.

  1. What "context issues" are you talking about?

  2. Repositories are usually not tested separately, you can just test services which run repository methods instead of writing tests for both. If you want to test repos anyway - fill the database with some data in @Before.

If you have more questions please ask.



来源:https://stackoverflow.com/questions/64570523/how-to-test-repository-with-junit5-and-testcontainers

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!