개발 이야기/Springboot

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

농개 2024. 1. 18. 20:50
반응형

앞서 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를 사용합니다.

 

반응형