나만의 안드로이드 앱 만들기(중급자 편) - 테스트 코드 작성하기 (utils)
테스트 코드는 간단하다면 간단하다고 느낄 수도 어렵다면 어렵다고도 느낄 수 있다고 생각합니다.
왜냐하면 어느 범위까지 작성해야 할지 고민이 많이 되기 때문입니다.
이번 편에서는 유틸 클래스와 뷰모델 2가지에 대한 테스트 코드를 다뤄보도록 하겠습니다.
유틸 클래스의 테스트 코드
유틸 클래스는 테스트 코드를 작성하기에 아주 편리합니다.
object CharFormatUtils {
fun amount(amount: Any?): String {
// null 이면 빈값으로 반환함
if (amount == null) {
return "0원"
}
return try {
val amountToLong = amount.toString().toLong()
val formatter = NumberFormat.getNumberInstance(Locale("ko_KR"))
val result = formatter.format(amountToLong)
return if (
amountToLong > 1000 &&
!result.contains(",")
) {
NumberFormat.getNumberInstance(Locale.getDefault()).format(amountToLong) + "원"
} else {
result + "원"
}
} catch (e: NumberFormatException) {
"0원"
}
}
}
CharFormatUtils 라는 유틸 클래스가 있습니다.
amount 는 UI 에 노출할 가격의 포맷을 만드는 메소드입니다.
유저에게 매번 노출되는 가격 정보이기 때문에 가격이 정확하게 표시되어야 하는 것이 중요합니다.
가격은 어떤 형태로 제공받게 될지 몰라 1000, "1000", null 이 3가지 경우의 수를 모두 충족하게 하였습니다.
저는 일반적으로 gpt 를 이용해서 뼈대를 잡고 살을 붙이는 식으로 테스트 코드를 작성합니다.
다음과 같은 예시를 추천 받았고 이를 기반으로 다음과 같이 작성하였습니다.
import wskim.aos.domain.utils.CharFormatUtils
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.MethodOrderer
import org.junit.jupiter.api.Order
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestMethodOrder
@TestMethodOrder(MethodOrderer.OrderAnnotation::class)
@DisplayName("문자열 형식 유틸 클래스 테스트")
class CharFormatUtilsTest {
@DisplayName("amount에 null 값을 전달하면 0원으로 반환되는가?")
@Order(1)
@Test
fun t01() {
val result = CharFormatUtils.amount(null)
assertEquals("0원", result)
}
@DisplayName("amount에 100 단위 이하 숫자 값을 전달하면 천 단위 구분 기호 없는 금액으로 반환되는가?")
@Order(2)
@Test
fun t02() {
val result = CharFormatUtils.amount(156)
assertEquals("156원", result)
}
@DisplayName("amount에 1000 단위 이상 숫자 값을 전달하면 천 단위 구분 기호를 포함한 금액으로 반환되는가?")
@Order(3)
@Test
fun t03() {
val result = CharFormatUtils.amount(1234567)
assertEquals("1,234,567원", result)
}
@DisplayName("amount에 100 단위 이하 문자 값을 전달하면 천 단위 구분 기호 없는 금액으로 반환되는가?")
@Order(4)
@Test
fun t04() {
val result = CharFormatUtils.amount("156")
assertEquals("156원", result)
}
@DisplayName("amount에 1000 단위 이상 문자 값을 전달하면 천 단위 구분 기호를 포함한 금액으로 반환되는가?")
@Order(5)
@Test
fun t05() {
val result = CharFormatUtils.amount("1234567")
assertEquals("1,234,567원", result)
}
@DisplayName("amount에 숫자 형식이 아닌 값을 전달하면 0원이 반환되는가?")
@Order(6)
@Test
fun t06() {
val result = CharFormatUtils.amount("문자열")
assertEquals("0원", result)
}
@DisplayName("amount에 소수점 형식이 값을 전달하면 0원이 반환되는가?")
@Order(7)
@Test
fun t07() {
val result = CharFormatUtils.amount("123.456")
assertEquals("0원", result)
}
@DisplayName("amount에 숫자 형식이 아닌 값을 포함한 숫자 값을 전달하면 0원이 반환되는가?")
@Order(8)
@Test
fun t08() {
val result = CharFormatUtils.amount("123a456")
assertEquals("0원", result)
}
}
우선 저는 Junit5 를 사용하여 테스트 코드를 작성하고 있습니다.
테스트 코드는 OrderAnnotation 및 Order 를 통해 순서대로 실행할 예정입니다.
메소드 명은 Order 에 맞춰 "테스트 + 순서" 로 작명하고 있습니다.
amount 메소드의 특징은 다음과 같습니다.
- 입력값의 null 허용은 하겠지만, 별도 처리는 하지 않겠다.
- NumberFormatException 이 발생해서는 안된다.
- 소수점은 취급하지 않습니다.
- 그 외에는 포맷이 정확하게 적용되어야 한다.
gpt 는 우선 7가지 케이스에 대해 추천해주었고 특징을 정확하게 짚은 것으로 생각됩니다.
그 외 숫자와 문자를 결합한 값을 전달하는 케이스 하나를 포함하였습니다.
정확하게 잘 동작 하는 것을 알 수 있습니다.
다음 편에서는 뷰 모델에서 테스트 코드를 작성해보도록 하겠습니다.
작성된 코드는 다음과 같습니다.
감사합니다.