问题
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:
- 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.
What "context issues" are you talking about?
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