테스트 케이스가 실패했다. BigDecimal을 사용한 숫자의 표현이 달라서였다.
기대값은 지수표기법이고, 결과값은 일반숫자형...
데이터를 저장하고 출력할땐 문제가 없었는데 테스트 케이스에서는 왜 오류가 났을까?
JavaScript Object Notation
JSON은 JavaScript 객체 문법으로 구조화된 데이터를 표현하기 위한 문자 표준 포맷이다.
{
"name": "치비",
"age" : 11
}
숫자의 표현 형식을 엄격하게 제한하지 않는다.
그렇기에 테스트에서 보여준 것과 같이 동일한 숫자라도 다양한 형태로 표현될 수 있다.
(8진수나 16진수 표기는 허용되지 않음)
{
"integer": 123, // 정수
"float": 123.45, // 일반적인 소수점 표기
"scientific": 1.2345e2, // 지수 표기법
"negative": -123.45 // 음수
}
여기서 일반 형식(고정소수점)은 소수점의 위치가 고정된 형태이고, 지수 형식(부동소수점)은 소수점의 위치가 움직이는 형태를 말한다.
BigDecimal 관련 이슈와 연결을 해보면 다음과 같다.
BigDecimal num1 = new BigDecimal("123.45"); // 일반 표기
BigDecimal num2 = new BigDecimal("1.2345E2"); // 지수 표기
// 둘 다 같은 값을 나타내지만 문자열 표현이 다름
System.out.println(num1); // 123.45
System.out.println(num2); // 1.2345E2
System.out.println(num1.equals(num2)); // true
@Serializable
data class Cat(
val name: String,
val age: Int
)
fun kotlinxSerializationExample() {
val cat = Cat("치비", 11)
// 직렬화
val json = Json.encodeToString(cat)
// 역직렬화
val deserializedPerson = Json.decodeFromString<Cat>(json)
}
직렬화는 객체나 데이터를 저장하거나 전송할 수 있는 형태로 변환하는 프로세스를 말한다.
직렬화 결과:
{
"name" : "치비",
"age" : 11,
"birth_date" : "2013-11-24"
}
역직렬화는 반대의 과정으로, 데이터나 객체를 원래의 구조로 복구하는 프로세스를 말한다.
역직렬화 결과:
Cat(name=치비, age=12, birthDate=2013-11-24)
내가 실행한 테스트는 캐싱 처리에 대한 내용이었다.
일반적으로 객체를 JSON으로 직렬화하여 캐시에 저장을 하고, 캐시에서 데이터를 가져와 역직렬화를 한다.
@Test
fun `캐시 저장 및 조회 테스트`() {
// given
val price = BigDecimal("1.2345E3")
val product = Product("item", price)
// when
cacheService.save("key", product)
val cached = cacheService.get("key")
// then
assertEquals(price, cached.price) // 여기서 실패
// price: 1.2345E3 (기대값)
// cached.price: 1234.5 (실제값)
}
직렬화 시 BigDecimal이 지수 표기법으로 저장이 되었고역직렬화 시 일반 숫자형으로 변환이 되어 발생한 문제였다.
val price: BigDecimal = price.stripTrailingZeros()
테스트 케이스에서도 커스텀 Serializer를 사용해서 타입을 맞추거나, compareTo()를 사용하여 해결하면 된다!
Runtime Error는 실행될때 발생하는 오류인데, 테스트 케이스에서 런타임 오류가 발생하지 않은 이유는 뭘까?
캐시에서 데이터를 가져올 때 역직렬화는 잘 되었기에 BigDecimal 타입 캐스팅 오류는 발생하지 않았다. 직렬화/역직렬화 과정에서 표현 방식이 다른거지 숫자 자체는 BigDecimal이기 때문이다.