-
redis mongodb testcontainer example 1편스프링 2023. 7. 20. 10:17
https://github.com/TaeWoonJeong/MongoRedisTestContainer
GitHub - TaeWoonJeong/MongoRedisTestContainer
Contribute to TaeWoonJeong/MongoRedisTestContainer development by creating an account on GitHub.
github.com
클론하고, MongoRedisSingleTestContainer 모듈에 가면 된다.
single이므로 redisconfig가 없어도 자동으로 localhost와 6379포트로 설정 되지만, 그래도 RedisConfig를 넣어줬다.
@Configuration @EnableRedisRepositories class RedisConfig( @Value("\${spring.data.redis.host}") private val redisHost: String, @Value("\${spring.data.redis.port}") private val redisPort: Int ) { @Bean fun redisConnectionFactory() = LettuceConnectionFactory(redisHost, redisPort) }
나머지 코드들은 간단하게 redis와 mongo에 값 추가와 조회기능이 있다.
embedded redis가 2020년이 마지막 커밋이어서, testcontainer로 한다.
위에서 RedisConfig파일에 @Value로 application.yml의 값을 가져다 사용하기 때문에,
@SpringBootTest를 사용하는 테스트코드에서도 application.yml 값을 넣어줘야한다.
없으면, 에러가 난다.
물론 RedisConfig파일을 삭제하고 application.yml 들을 삭제하면, 정상작동한다.
테스트코드 설명
@SpringBootTest class CommonDependencyConfig { @Autowired lateinit var userRedisRepository: UserRedisRepository @Autowired lateinit var userMongoRepository: UserMongoRepository @Autowired lateinit var dbService: DBService }
addMongoTest, getMongoTest, addRedisTest, getRedisTest에서 필요한 위존성들을 위에서 한번에 autowired해준다.
@Configuration @Testcontainers class TestContainerMongoConfig : CommonDependencyConfig() { companion object { private const val MONGO_DOCKER_IMAGE = "mongo:latest" @Container val MONGO_CONTAINER = GenericContainer( DockerImageName.parse(MONGO_DOCKER_IMAGE) ).withExposedPorts(27017) .withReuse(true) init { MONGO_CONTAINER.start() } } }
@Configuration @Testcontainers class TestContainerRedisConfig : CommonDependencyConfig() { companion object { private const val REDIS_DOCKER_IMAGE = "redis:latest" @Container val REDIS_CONTAINER = GenericContainer( DockerImageName.parse(REDIS_DOCKER_IMAGE) ).withExposedPorts(6379) .withReuse(true) init { REDIS_CONTAINER.start() } } }
CommonDependencyConfig를 상속받고, 각자 컨테이너들을 시작해준다.
@TestContainers 어노테이션이 없으면, 한번 만든 컨테이너에서 계속 실험하므로, 결과가 틀리게 된다.
@TestContianers 어노테이션을 붙이면, 컨테이너가 테스트마다(클래스마다) 재생성되므로, 만든다음, 아래의 dynamicPropertySource로 매핑해줘서 작동한다.
class AddRedisTest : TestContainerRedisConfig() { companion object { @JvmStatic @DynamicPropertySource fun overrideProps(registry: DynamicPropertyRegistry) { registry.add("spring.data.redis.host") { REDIS_CONTAINER.host } registry.add("spring.data.redis.port") { REDIS_CONTAINER.getMappedPort(6379) } // registry.add("spring.data.redis.port") { REDIS_CONTAINER.firstMappedPort } } } @BeforeEach fun setup() { val address: String = REDIS_CONTAINER.host val port: Int = REDIS_CONTAINER.firstMappedPort println(address + port + "입니다.") } @Test fun addRedisTest() { dbService.addRedis("email", "name") val redis = dbService.getRedis() Assertions.assertEquals(redis.size, 1) } }
addRedisTest를 예를 들면, Redis를 사용하므로, 위에서 생성한 컨테이너 설정을 상속받아주고,
@DynamicPropertySource로 port와 host를 설정해준다.
이때 @JvmStatic을 넣어야하는데, 없으면 application.yml에서 설정한 포트로 간다.
즉 컨테이너를 만드는데, 컨테이너에서 테스트하지 않고, 로컬에서 테스트가 된다.
MongoDB테스트도 똑같은데, 역시 @JvmStatic이 없으면, 로컬 몽고디비에 테스트를 하므로 실패한다.
https://velog.io/@suev72/JvmStatic%EA%B0%80-%EB%AC%B4%EC%97%87%EC%9D%BC%EA%B9%8C
@JvmStatic가 무엇일까?
안드로이드 New->Fragment 로 프래그먼트를 생성해보면, 이렇게 newInstance함수를 자동으로 만들어주는데, @JvmStatic이라는 어노테이션을 볼 수 있다. @JvmStatic가 뭘까? > 결론: Java의 static 처럼 쓰기 위함
velog.io
추측하자면, companion object로 설정을 해주면, 밖에서 설정을 읽지 못해서, JvmStatic을 붙여줘야 컨테이너에 테스트를 시키는거 같다.
아쉬운점은, 만약
class AddMongoTest : TestContainerMongoConfig() { companion object { @JvmStatic @DynamicPropertySource fun overrideProps(registry: DynamicPropertyRegistry) { registry.add("spring.data.mongodb.host") { MONGO_CONTAINER.host } // registry.add("spring.data.mongodb.port") { MONGO_CONTAINER.getMappedPort(27017).toString() } registry.add("spring.data.mongodb.port") { MONGO_CONTAINER.firstMappedPort.toString() } } } @BeforeEach fun setup() { val address: String = MONGO_CONTAINER.host val port: Int = MONGO_CONTAINER.firstMappedPort println(address + port + "입니다.") } @Test fun addMongoTest() { dbService.addMongo("email", "name") val mongo = dbService.getMongo() Assertions.assertEquals(mongo.size, 1) } @Test fun addMongoTest2() { dbService.addMongo("email", "name") val mongo = dbService.getMongo() Assertions.assertEquals(mongo.size, 1) } }
이렇게 만든 경우, 하나의 컨테이너에서 2번 테스트하는게 되어서, 둘 중 하나의 테스트는 실패한다.
이부분 해결책을 찾아보겠다.
다음은, 레디스 레플리케이션과 몽고디비 레플리케이션 설정을 하고, 테스트컨테이너로 테스트 해보겠다.
'스프링' 카테고리의 다른 글
코틀린에서 log 사용하기 (0) 2023.07.04