728x90
반응형
source 는 Github 에 있습니다.
목차는 테스트 & 리팩토링 목차 에 있습니다.
[테스트&리팩토링 7편] TestContainer Example
TestContainer 란?
- DB, 큐, 메시지 브로커 등을 제공해주는 가상 컨테이너입니다. Java, Kotlin 과 같은 JVM 기반에서 동작하며, Docker 를 필요로 합니다.
- docker-compose 는 언어와 관계 없이 사용할 수 있으며, TestContainer 는 코드 레벨에서 제어할 수 있습니다.
- 코드에서 제어할 수 있기에 docker 만 떠있다면 테스트 코드에 container 기동, 중단 로직을 넣어서 테스트를 수행할 때, 한 번에 수행할 수 있는 특징이 있습니다.
소스 설명
Spring boot, spring data jpa, MySQL 환경에서 DB 컨테이너를 띄워서 DB CRUD 를 진행하는 예제를 작성했습니다.
DB 만 테스트 하기 위해
@DataJpaTest
를 사용했습니다.소스
Test Source 와 Container, DataSource Config 를 작성했습니다. DataSource 를 빈초기화 할 때는, TestMySQLContainer 작업이 끝나야 MySQL DB Container 가 생성되기에 DependsOn 을 설정했습니다.
나머지 소스는 github 에 있습니다.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// UserRepositoryTest.java | |
@DataJpaTest | |
@Import(TestMySQLContainer::class, DataSourceConfig::class) | |
class UserRepositoryTest { | |
// lateinit 이 변수가 나중에 초기화될 것이며, 선언할 때 즉시 초기화할 필요가 없다는 것을 의미 | |
@Autowired | |
private lateinit var userRepository: UserRepository | |
@Test | |
fun `given User when findById then return User`() { | |
// given | |
val user = User(name = "HelloWorld...") | |
userRepository.save(user) | |
// when | |
val result = userRepository.findById(user.id!!) | |
// then | |
assertEquals(user, result.get()) | |
} | |
} | |
// DataSourceConfig.java | |
@TestConfiguration | |
class DataSourceConfig { | |
@Bean | |
@DependsOn("TestMySQLContainer") | |
fun dataSource(): HikariDataSource { | |
return DataSourceBuilder.create() | |
.type(HikariDataSource::class.java) | |
.url(TestMySQLContainer.container.jdbcUrl) | |
.username(TestMySQLContainer.container.username) | |
.password(TestMySQLContainer.container.password) | |
.build() | |
} | |
} | |
// TestMySQLContainer.java | |
@TestConfiguration("TestMySQLContainer") | |
class TestMySQLContainer { | |
companion object { | |
val logger = LoggerFactory.getLogger(TestMySQLContainer::class.java) | |
@Container | |
@JvmStatic | |
val container = MySQLContainer<Nothing>("mysql:8.0.23") | |
.apply { | |
withDatabaseName("test") | |
withUsername("root") | |
withPassword("1234") | |
} | |
.apply { | |
start() | |
} | |
.apply { | |
followOutput(Slf4jLogConsumer(logger)) | |
} | |
} | |
} |
SharedContainer
- Container annotation 을 사용하면 테스트 클래스가 수행될 때마다 새로운 인스턴스가 생성되므로, 테스트 간에 영향을 주지 않습니다. Shared Container 는 생성한 인스턴스를 재사용하는 것이기에 각각의 테스트에서는 인스턴스를 공유해서 사용할 수 있으며, 새로 생성할 필요가 없기에 부하가 줄게 됩니다.
- 상황에 맞게 Container 를 쓸지 SharedContainer 를 쓸지 판단해서 쓰면 좋을 것 같습니다.
'test & refactoring' 카테고리의 다른 글
[테스트 및 리팩토링 9편] Junit5 정리 (2) | 2023.10.10 |
---|---|
[테스트 및 리팩토링 8편] fixture-monkey 정리 (0) | 2023.05.05 |
[테스트 & 리팩토링 6편] 팩토리 패턴 if else 줄이기 (map, functional interface 사용) (2) | 2022.08.01 |
[테스트 & 리팩토링 4편] github pull request template 및 CodeReview 정리 (0) | 2022.06.27 |
[테스트 & 리팩토링 3편] package layer, package import 정리 (0) | 2022.06.27 |
댓글