DI 에 대한 두번째 포스팅입니다.
첫번째 게시글은 아래를 링크로!
https://velog.io/@king-jungin/Dependency-Injection-%EA%B0%80-%EC%99%9C-%ED%95%84%EC%9A%94%ED%95%9C%EA%B0%80%EC%9A%94..-1
이전 포스팅에서 의존성 주입은 Tesable 한 코드를 작성할 수 있다고 했습니다.
과연 Testable 한 코드는 무엇일까요?
아래에 요구사항에 따른 코드가 있습니다.
요구사항
1. 랜덤한 숫자를 가진 랜덤박스가 있습니다.
2. 이 랜덤박스는 랜덤한 숫자가 90 이상인 경우에만 상품이 들어있습니다.
코드
object Goods
class RandomBox {
private val score = Random(System.currentTimeMillis()).nextInt(100)
fun unBoxing() = if (score >= 90) {
Goods
} else {
null
}
}
자! 이제 우리는 이 코드가 잘 동작하는지 확인하고 싶습니다.
그 중에 실제로 랜덤한 숫자 score
가 90
이상이면 Goods
를 반환해 주는지 테스트하고 싶은데요.
여기서 문제가 있습니다.
score
가 90
이상인 상황을 테스트하기 위해서는
바람직하지 않습니다. 언제 나올줄 알고 돌려보나요...
Random
로직을 주석 처리하고 score
에 정수 90을 넣어 재빌드한다.🤮이 또한 바람직하지 않습니다.
물론 현재로선 간단하겠지만, 로직이 복잡해지면 주석 처리할 곳이 많아져 테스트가 심히 어려워집니다.
그렇다면 어떻게 해야할까요??
RandomInt.kt
interface RandomInt {
operator fun invoke(): Int
}
class RandomIntImpl: RandomInt {
override fun invoke() = Random(System.currentTimeMillis()).nextInt(100)
}
RandomBox2.kt
class RandomBox2(
random: RandomInt
) {
private val score = random()
fun unBoxing() = if (score >= 90) {
Goods
} else {
null
}
}
Main.kt
fun main(args: Any) {
val goods = RandomBox2(RandomIntImpl()).unBoxing()
// ...
}
위 코드는 의존성 주입으로 구현된 코드입니다.
RandomInt
는 랜덤 정수를 반환하는 로직을 추상화한 interface 입니다.RandomIntImpl
에서 구현합니다.RandomBox2
는 추상화된 RandomInt
interface 를 주입받아 score
에 값을 할당합니다.즉, 랜덤 정수를 추출하는 로직을 추상화하여 주입하고 있으므로 다양한 알고리즘의 랜덤 로직을 주입하여 사용할 수 있고, 테스트용 랜덤 로직을 작성하여 주입할 수도 있게 되었습니다.
아래는 score
가 90
이상인 Case 테스트의 예시입니다.
RandomIntTestImpl
class RandomIntTestImpl: RandomInt {
override fun invoke() = 90
}
main.kt
fun main(args: Any) {
val goods = RandomBox2(RandomIntTestImpl()).unBoxing()
// ...
}
RandomIntTestImpl
클래스가 정수 90
만을 반환도록 구현되어 있으므로, 이를 주입하여 Goods
가 반환되는지에 대한 테스트가 가능하게 되었습니다.
이를 응용하여 Junit 및 Mockito 등을 활용한 Unit Test 가 가능합니다.
--> 다음 포스팅에 계속..