본문 바로가기
Java & Kotlin/Spring

MySQL Docker container를 이용한 통합 테스트 시 한글 깨짐 이슈

by devson 2021. 4. 7.

Spring Application 통합 테스트 시 H2 같은 in-memory DB를 사용할 수 있지만
최대한 운영 환경과 유사한 상황에서 테스트하고자 한다면 Testcontainers를 통해 테스트 용 DB container를 띄우는 방식도 고려할 수 있을 것이다.

 

이번 포스팅은 MySQL Docker container를 사용하여 통합 테스트 시 인코딩 관련 이슈와 이를 해결하기 위해 인코딩 설정하는 방법에 대해 알아보겠다.

 

관련 코드는 여기에서 확인 가능하다.


인코딩 관련 이슈를 테스트를 재현하기 위해 MySQL, JPA dependency를 추가하고 SpringBoot Application을 생성한 뒤
Testcontainers JDBC MySQL depdencey를 추가한다.

 

그리고 다음과 같이 Entity, Repository를 세팅한다.

import javax.persistence.Column
import javax.persistence.Entity
import javax.persistence.Id

@Entity
data class User(
    @Id
    val id: Long,

    @Column
    var name: String,
)
import org.springframework.data.jpa.repository.JpaRepository

interface UserRepository : JpaRepository<User, Long>

 

application.properties는 아래와 같이 세팅한다.

spring.jpa.generate-ddl=true
spring.jpa.hibernate.ddl-auto=create
spring.jpa.show-sql=true

 

세팅이 되었으면 이슈 재현을 위한 통합 테스트를 짜보자.

import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.test.context.DynamicPropertyRegistry
import org.springframework.test.context.DynamicPropertySource
import org.testcontainers.containers.MySQLContainer

@SpringBootTest
class MysqlencodingApplicationTests {
    companion object {
        private val mysqlContainer = MySQLContainer<Nothing>("mysql:5.7").apply {
            start()
        }

        @JvmStatic
        @DynamicPropertySource
        fun registerDbProperties(properties: DynamicPropertyRegistry) {
            properties.add("spring.datasource.url", mysqlContainer::getJdbcUrl)
            properties.add("spring.datasource.username", mysqlContainer::getUsername)
            properties.add("spring.datasource.password", mysqlContainer::getPassword)
        }
    }

    @Autowired
    lateinit var userRepository: UserRepository

    @Test
    @DisplayName("한국어 저장 테스트")
    fun koreanTest() {
        userRepository.saveAll(
            listOf(
                User(1L, "Chris"),
                User(2L, "손한국")
            )
        )

        assertThat(userRepository.findById(1L).get().name).isEqualTo("Chris")
        assertThat(userRepository.findById(2L).get().name).isEqualTo("손한국")
    }
}

 

@Testcontainers, @Container 어노테이션을 사용하지 않은 이유는 테스트 마다 중복해서 Container를 띄우는 것을 막기 위해 최초 application context 세팅 시 한 번만 Container를 띄우게 하기 위함이다.
관련해서는 언젠가 다른 포스팅에서... 참고

 

모든 세팅이 끝났다면 테스트를 실행시켜보자.

테스트 결과 영어와 같은 경우 정상적으로 값을 가져왔지만 한국어의 경우 위의 결과와 같이 ???로 값을 가져온 것을 확인할 수 있다.

 

이는 MySQL DB 인코딩 설정으로 인해 발생한 오류로
직접 테스트 MySQL container에 접속하여 값을 조회하면 다음과 같이 영어는 잘 저장되나 한국어는 ???로 저장된 것을 확인할 수 있다.

 

이 이슈를 해결하기 위해서는 MySQL DB 인코딩 설정이 필요한데
이는 단순하게 MySQL container 실행 후 Character Set을 지정하는 command를 실행 시켜주면 된다.

@SpringBootTest
class MysqlencodingApplicationTests {
    companion object {
        private val mysqlContainer = MySQLContainer<Nothing>("mysql:5.7").apply {
            withCommand("mysqld", "--character-set-server=utf8mb4") // Character Set 설정
            start()
        }

        @JvmStatic
        @DynamicPropertySource
        fun registerDbProperties(properties: DynamicPropertyRegistry) {
            properties.add("spring.datasource.url", mysqlContainer::getJdbcUrl)
            properties.add("spring.datasource.username", mysqlContainer::getUsername)
            properties.add("spring.datasource.password", mysqlContainer::getPassword)
        }
    }

    // ...
}

 

그리고 다시 테스트를 실행시키면 아래와 같이 정상적으로 테스트가 통과되는 것을 확인할 수 있다.

댓글