테스트를 쉽고 편리하게, Fixture Monkey
"Write once, Test anywhere"
네이버에서 오픈소스로 개발되고 있는 테스트 객체 생성 라이브러리이다. 아마도 이름은 넷플릭스의 오픈소스, Chaos Monkey 에서 따온 듯하다. 랜덤으로 테스트 픽스처를 생성해주기 때문에, 실제로 카오스 엔지니어링을 하는 체험을 할 수 있다.
약 2년 전 처음 접한 이후, 가장 좋아하는 오픈소스 라이브러리 중 하나가 되었다. 어쩌다보니 글도 2편이나 썼다.
이후로 버전이 변할 때마다 변경점이 너무 많아 추가적인 글을 안적고 있다가, 최근 1.x 가 릴리즈되었기에 새로운 마음으로 다시 소개글을 써본다.
이전 글에서는 Java 를 기준으로 글을 작성했지만, 최근 추세에 맞춰서 Kotlin 으로 작성한다. 글 내용은 공식 문서를 기반으로 실제 사용 후기를 좀 섞었다.
왜 Fixture Monkey 가 필요한가
아래 같은 코드를 보면서 기존 방식에서 어떤 점이 문제인지 살펴보자.
Java 개발자들에게 익숙한 JUnit5 를 사용하여 예제를 작성했다. 하지만 개인적으로 Kotlin 환경에서는 Kotest를 사용하는 것을 추천한다.
data class Product (
val id: Long,
val productName: String,
val price: Long,
val options: List<String>,
val createdAt: Instant,
val productType: ProductType,
val merchantInfo: Map<Int, String>
)
enum class ProductType {
ELECTRONICS,
CLOTHING,
FOOD
}
@Test
fun basic() {
val actual: Product = Product(
id = 1L,
price = 1000L,
productName = "productName",
productType = ProductType.FOOD,
options = listOf(
"option1",
"option2"
),
createdAt = Instant.now(),
merchantInfo = mapOf(
1 to "merchant1",
2 to "merchant2"
)
)
// 테스트 목적에 비해 준비 과정이 길다
actual shouldNotBe null
}
테스트 객체 생성의 어려움
테스트 코드를 살펴보면 assertion 을 위해 객체를 생성 하기 위해 작성해야 하는 코드가 너무 많다고 느껴진다. 구현 내용상 프로퍼티를 설정하지 않으면 컴파일 에러가 발생하기 때문에, 무의미한 프로퍼티라도 반드시 작성해줘야 한다.
이렇게 테스트 코드에서 assertion 을 위해 준비해야하는 부분이 길어지면, 코드에 테스트 목적에 대한 의미가 불분명해질 수 있다. 처음 이 코드를 읽는 사람은 아무 의미 없는 프로퍼티여도 숨은 의미가 있는지 살펴봐야하기 때문이다. 이 과정은 개발자들의 피로감을 높인다.
엣지 케이스 인식의 어려움
직접 프로퍼티를 설정하여 객체를 생성할 경우, 프로퍼티가 고정되기 때문에 다양한 시나리오에서 나타날 수 있는 엣지 케이스를 놓치는 경우가 많다.
val actual: Product = Product(
id = 1L, // 만약 id 가 음수가 되면 어떨까?
// ...생략
)
엣지 케이스를 찾기 위해서는 하나하나 개발자가 프로퍼티를 설정해가며 검증해줘야 하는데, 실제로는 런타임에 에러가 발생한 이후에나 엣지 케이스에 대해 눈치채게 되는 일이 부지기수다. 에러가 발생하기 전에 엣지 케이스를 수월하게 발견하기 위해서는 객체의 프로퍼티가 어느 정도 랜덤성을 갖고 설정되야 한다.