GitHub - pbg0205/concert
Contribute to pbg0205/concert development by creating an account on GitHub.
github.com
νμ¬ μ¬μ΄λ νλ‘μ νΈμμ λ‘컬 νκ²½μμ main κ³Ό test μ DB νκ²½μ λ 립μ μΌλ‘ ꡬμ±νκΈ° μν΄ test container λ₯Ό μ μ©νλ€. Test Container λ₯Ό μ μ©νλ©° κ²½ννλ μ½μ§ κΈ°λ‘μ κΈ°λ‘ν΄λ³΄κ³ μ νλ€.
[1] test container λ₯Ό μ¬μ©νλ μ΄μ

- μ€μ μλΉμ€μ λμΌν νκ²½ : Docker λ₯Ό μ¬μ©ν΄ DB, MQ, API λ± μΈλΆ μμ€ν μ μ€μ μ΄μ νκ²½μ μ μ¬ν νκ²½μμ ν μ€νΈν μ μλ μ₯μ μ΄ μλ€.
- ν μ€νΈ λ λ¦½μ± λ³΄μ₯ : κ° ν μ€νΈλ₯Ό λ 립λ 컨ν μ΄λμμ μ€νλλ―λ‘ ν μ€νΈ κ³ λ¦½μ±μ 보μ₯ν μ μλ€.
[2] ν μ€νΈ 컨ν μ΄λ κ΅¬μ± λ°©λ² (with.gradle)
(1) build.gradle
ext {
set('testcontainers.version', "1.19.8")
}
dependencies {
testImplementation("org.springframework.boot:spring-boot-testcontainers")
testImplementation("org.testcontainers:junit-jupiter")
testImplementation("org.testcontainers:mysql")
}
(2) ν μ€νΈ 컨ν μ΄λ μμ± λ°©λ²
ν μ€νΈ 컨ν μ΄λλ₯Ό μ¬μ©νκΈ° μν΄μλ @TestContainers, @Container κ° νμνλ€.
- @TestContainers
- ν΄λΉ ν μ€νΈ ν΄λμ€κ° TestContainers λ₯Ό μ¬μ©ν κ²μ μ μΈνλ ν΄λμ€ λ 벨 μ΄λ Έν μ΄μ (ElementType.TYPE)μ΄λ€.
- ν΄λΉ μ΄λ Έν μ΄μ μ΄ λΆμ ν΄λμ€μμ μ μΈλ @Container νλμ μλͺ μ£ΌκΈ°λ₯Ό κ΄λ¦¬νλ©°, ν μ€νΈ μμ μ 컨λ€μ΄λλ₯Ό μλμΌλ‘ μμνκ³ , ν μ€νΈ μ’ λ£ μ μ 리λ₯Ό μννλ€.
- TestContainer λ₯Ό μ¬μ©νλ λͺ¨λ ν μ€νΈ ν΄λμ€μ λ°λμ μ μΈν΄μΌ νλ€.
- @Container
- ν μ€νΈμμ μ¬μ©ν 컨ν μ΄λλ₯Ό μ μνλ μ΄λ Έν μ΄μ μ΄λ€.
- ν΄λΉ νλκ° TestcContainers κ° κ΄λ¦¬νλ 컨ν μ΄λμμ λνλ΄λ©° λ©€λ² λ³μ λ 벨(ElementType.FIELD) μ΄λ€.
- @Container λ‘ κΈ°λ³Έμ μΌλ‘ μ μΈλ 컨ν μ΄λν ν μ€νΈ μμ μ μλ μμ±, μ’ λ£ μ μλ μ 리λλ€.
- 컨ν μ΄λλ₯Ό static μΌλ‘ μ μΈνλ©΄, ν μ€νΈ ν΄λμ€μ λͺ¨λ λ©μλκ° κ°μ 컨ν μ΄λλ₯Ό 곡μ νλ€.
@Testcontainers
public abstract class RestDocsDocumentationTest {
@Container
static MySQLContainer<?> MYSQL_CONTAINER = new MySQLContainer<>(DockerImageName.parse("mysql:8.0"))
.withDatabaseName("concert_db")
.withUsername("root")
.withPassword("concert2025");
@BeforeAll
static void beforeAll() {
MYSQL_CONTAINER.start();
}
@AfterAll
static void afterAll() {
MYSQL_CONTAINER.stop();
}
}
(3) application.yml μ€μ
ν μ€νΈ 컨ν μ΄λ μ μ© spring.datasource.url κ³Ό spring.datasource.driver-class-name μ μ€μ ν΄μΌ νλ€.
- spring.datasource.url : jdbc:tc:[image:version]://[db-name]
- spring.datasource.driver-class-name: org.testcontainers.jdbc.ContainerDatabaseDriver
spring:
datasource:
url: jdbc:tc:mysql:8://concert_db
username: root
password: concert2025
driver-class-name: org.testcontainers.jdbc.ContainerDatabaseDriver
[3] test container μ½μ§ κΈ°λ‘
(1) ν μ€νΈ 컨ν μ΄λ μ¬μ¬μ©ν λ @Configuration μ κ³ λ €ν΄λ³΄μ.
class λ¨μμμ @TestContainers λ₯Ό μ¬μ©νλ©΄ ν΄λμ€ λ¨μμ 컨ν μ΄λ λΌμ΄ν μ¬μ΄ν΄ κ΄λ¦¬λ§ κ°λ₯νλ€. μ¦, ν μ€νΈ ν΄λμ€ μ€ν, μ’ λ£ λ¨μμμλ§ λΌμ΄ν μ¬μ΄ν΄μ΄ κ°λ₯νλ€.

νμ§λ§, @Configuration μ ν΅ν @PreDestroy λ₯Ό μ¬μ©νλ©΄ ν μ€νΈ 컨ν μ΄λλ₯Ό μ’ λ£νλ μμ μ 컨ν μ΄λλ₯Ό μ’ λ£ν΄ μ€ν, μ’ λ£λ₯Ό μ΅μννμ¬ ν μ€νΈ μ€ν μκ°μ μ€μΌ μ μλ€.
λν, @Configuration μ μ μΈνλ©΄ ν΅ν© ν μ€νΈλ₯Ό λμμν€κΈ° μν μ€μ μΌλ‘ λ±λ‘λκ³ static ν€μλλ₯Ό ν΅ν΄ TestContainer λ₯Ό μ¬μ¬μ©νκ³ μμ΄ TestContext CachingμΌλ‘ μΈν λ‘λ© μλμ μ₯μ μ΄ μμ κ²μΌλ‘ μμνλ€. (μΆκ°μ μΈ κ²ν κ° νμ)
@Testcontainers
@Configuration
public class TestContainerConfiguration {
@Container
static MySQLContainer<?> MYSQL_CONTAINER = new MySQLContainer<>(DockerImageName.parse("mysql:8.0"));
static {
MYSQL_CONTAINER.start();
}
@DynamicPropertySource
static void configureProperties(DynamicPropertyRegistry registry) {
registry.add("spring.datasource.url", MYSQL_CONTAINER::getJdbcUrl);
registry.add("spring.datasource.username", MYSQL_CONTAINER::getUsername);
registry.add("spring.datasource.password", MYSQL_CONTAINER::getPassword);
}
@PreDestroy
void preDestroy() {
if (MYSQL_CONTAINER.isRunning()) {
MYSQL_CONTAINER.stop();
}
}
}
(2) ν μ€νΈ 컨ν μ΄λλ₯Ό μ¬μ©ν λ ddl-auto option=create λ₯Ό μ¬μ©νκΈ°
ν μ€νΈ 컨ν μ΄λλ₯Ό λμ νκ³ ν μ€νΈκ° μλ£λ νμλ ν μ€νΈλ₯Ό μ’ λ£νμ§ μλ μ΄μκ° μμλ€. κ²°κ΅ ν μ€νΈκ° μ±κ³΅νμ¬ μ’ λ£λ λμμ§λ§ μ’ λ£νκΈ° μν μκ° μ§μ°μΌλ‘ μΈν λΉλ μκ°μ΄ κΈΈμ΄μ‘λ€.
μμΈ νμΈμ μν΄ λ‘κ·Έλ₯Ό νμΈν΄λ³΄λ drop table νλ κ³Όμ μ μ§ννλ€ connection μ΄ λμ΄μ§λ λ¬Έμ μλ€. drop table μ νλ κ³Όμ μμ ν μ€νΈ 컨ν μ΄λκ° λ¨Όμ μ’ λ£λμ΄ drop table μ μ¬μλνκΈ° μν΄ connection λ°λ³΅ μλνλ€ κ²°κ΅ μ€ν¨νλ€.

drop table μ΄ μ€ν¨νλ©΄μ Test Container μμλ νμνμ§ λͺ»ν΄ 컨ν μ΄λκ° μμ λμ§ λͺ»ν κ²μ νμΈν μ μλ€.

νμ¬ μλ° μ½λλ₯Ό ν΅ν΄μ TestContainer lifecycle μ μ μ΄νλλ° νκ³κ° μμ΄ κΈ°μ‘΄ spring.jpa.hibernate.ddl-auto μ΅μ μ create-drop μμ create λ‘ λ³κ²½νλ€. create-drop μ ν μ€νΈκ° μ’ λ£λλ©΄ drop table μ νΈμΆνλ λ°λ©΄, create λ ν μ€νΈκ° μμλλ μμ μ drop table μ νΈμΆνμ¬ TestContainer μ lifecycle μ μ μ΄νμ§ μκ³ ν΄κ²°ν μ μλ λ°©λ²μ΄μλ€.


(4) μ΄νμ Gradle BuildService λ νλ² κ²ν ν΄λ³΄μ.
μ΄μ μλ μΈκΈνλ€μνΌ java code level μμ ν μ€νΈ 컨ν μ΄λμ λΌμ΄ν μ¬μ΄ν΄μ μ‘°μ νλλ° νκ³κ° μλ€. μ΄λ₯Ό κ°μ ν μ μλ λ°©λ² μ€ νλκ° Gradle BuildService λΌκ³ νλ€.
Gradle BuildService λ task μ¬μ΄μ μνλ 리μμ€λ₯Ό 곡μ νκ² ν΄μ£Όλ μΈν°νμ΄μ€μ΄λ€. μ΄λ₯Ό ν΅ν΄ Container λ₯Ό λ±λ‘νμ¬ integration test μμ μ¬μ©ν μ μκ² λ§λ€μ΄μ£Όλ©΄ java code level λ³΄λ€ λμ± λμ λ²μλ‘ TestContainer lifecycle μ μ μ΄κ° κ°λ₯νλ€. ν΄λΉ λ΄μ©μ μ΄νμ λ€μ κ²ν ν΄λ³Ό μμ μ΄λ€.
Reference
- [Testcontainer]Getting started with Testcontainers in a Java Spring Boot Project : https://testcontainers.com/guides/testing-spring-boot-rest-api-using-testcontainers/
- [Testcontainer] Testcontainers container lifecycle management using JUnit 5 : https://testcontainers.com/guides/testcontainers-container-lifecycle/
'π backend > test' μΉ΄ν κ³ λ¦¬μ λ€λ₯Έ κΈ
| docker -compose κΈ°λ° λ‘컬 DB λͺ¨λν°λ§ ꡬμΆ(mysqld-exporter + prometheus + grafana) (0) | 2025.01.25 |
|---|---|
| K6 tutorial (0) | 2024.12.04 |
| nGrinder tutorial (0) | 2024.03.19 |
| pinpoint simple summary (0) | 2024.03.08 |
