본문 바로가기
개발 이야기/Springboot

Testcontainers로 테스트 코드 만들기 2(with Kotlin)

by 농개 2024. 1. 18.
반응형

앞서 Java로 작성했던 Testcontainers로 테스트 코드 만들기

Kotlin으로도 작성해봅시다.

 

이번에는 Mysql이 아닌 Redis를 사용한다고 가정합니다.

또한 Webflux 기반 테스트 환경 구축방법에 대해 포스팅합니다.

 

로컬환경은 아래와 같습니다.

  • Windows 10
  • JDK 17
  • Kotlin 1.8
  • Springboot 3.1.4
  • Testcontainers 1.17.7

1. 의존성 추가

아래와 같이 build.gradle.kts에 의존성을 추가해줍니다.

/* build.gradle.kts */
dependencies {
	...(중략)
    testImplementation("io.mockk:mockk:1.10.4")
    testImplementation("org.junit.jupiter:junit-jupiter:5.8.1")
    testImplementation("org.testcontainers:testcontainers:1.17.6")
    testImplementation("org.testcontainers:junit-jupiter:1.17.6")
 }

 

 

2. 코드 추가

Springboot에서 Redis 사용을 위한 아래 컴포넌트를 추가해줍니다.

@Configuration
class RedisConfig {
    @Bean
    fun reactiveRedisTemplate(reactiveRedisConnectionFactory: ReactiveRedisConnectionFactory): ReactiveRedisTemplate<String, Any> {
        val serializer = Jackson2JsonRedisSerializer(Any::class.java)
        val builder = RedisSerializationContext.newSerializationContext<String, Any>(StringRedisSerializer())
        val context = builder.value(serializer).build()

        return ReactiveRedisTemplate(reactiveRedisConnectionFactory, context)
    }
}

 

다음에는 실제 테스트 코드를 작성해봅시다.

 

 

3. 추상클래스 추가

아래와 src/test 내에 추상 클래스를 작성해봅니다.

@SpringBootTest
@ActiveProfiles("test")
abstract class IntegrationTest {

    companion object {
        private var redis: GenericContainer<*>
        private val REDIS_IMAGE_NAME = "redis:6.2.7-alpine"
        private val PORT = 6379

        init {
            redis = GenericContainer(REDIS_IMAGE_NAME)
                    .withExposedPorts(PORT)
                    .withReuse(true)
        }

        @JvmStatic
        fun get(): GenericContainer<*> {
            return redis;
        }

        @JvmStatic
        @BeforeAll
        fun beforeAll() {
            if (!redis.isRunning()) {
                redis.start()
            }
        }

        @JvmStatic
        @AfterAll
        fun afterAll() {
            redis.close()
        }

        @JvmStatic
        @DynamicPropertySource
        fun properties(registry: DynamicPropertyRegistry) {
            registry.add("spring.data.redis.host", redis::getHost)
            registry.add("spring.data.redis.port", redis::getFirstMappedPort)
        }
    }    
}
  • 추상클래스내에 static 멤버를 추가합니다.
  • 클래스 초기화 시 static 멤버가 생성되고 이 때 RedisContainer를 띄우게 됩니다.
  • @JvmStatic 어노테이션으로 static 멤버로 만들어 줄 수 있습니다.
  • @DynamicPropertySource 어노테이션으로 Springboot가 연동할 Redis의 host/port를 동적으로 변환해줍니다.

이제 이 추상클래스를 상속 받아 API 테스트 코드를 작성해봅시다.

 

4. API 테스트 코드 추가

@ExtendWith(MockitoExtension::class)
@ExtendWith(SpringExtension::class)
@AutoConfigureWebTestClient
class HelloControllerTest @Autowired constructor(
        val webTestClient: WebTestClient
) : IntegrationTest() {

    @Test
    fun `redis 입력 테스트`() {
        val data = """
            {
                "key": "test",
                "field":"2",
                "value":"abc"
            }
        """.trimIndent()

        webTestClient.post()
                .uri("/api/hello/redis")
                .contentType(MediaType.APPLICATION_JSON)
                .body(BodyInserters.fromValue(JsonUtil.convertToMap(data)))
                .exchange()
                .expectStatus().isOk
    }
}
  • IntegrationTest 클래스를 상속받습니다.
  • 여기서는 Webflux를 사용하기 때문에 API 테스트 도구로 MockMvc가 아닌 WebTestClient를 사용합니다.

 

반응형