언어/Kotlin
Mockk(relaxed = true) 는?
AlgoPoolJa
2023. 3. 13. 23:00
테스트 코드를 짜다보면 특정 클래스의 메서드가 특정 방식이 반환되기를 기대할 때 종종 Mock을 이용해 테스트를 짭니다. 언어마다 여러가지 목킹 도구들이 있고, 그중 코틀린은 Mockk 가 주로 사용됩니다.
코틀린의 테스트 코드를 보면 모킹을 다룰 때 mockk(relaxed = true) 로 되어있는것을 볼 수 있습니다. relaxed = true 를 파라미터로 줄 때와 그렇지 않을 때의 사용방법이 어떻게 다른지 비교해보겠습니다.
relaxed = true
// Member.kt
@Entity
class Member(
@Column(name = "name")
val name: String,
) {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private val id: Long? = null
@Column(name = "deleted_at")
private val deletedAt: String? = null
}
// PaymentService.kt
@Service
class PaymentService(private val memberRepository: MemberRepository) {
fun getBoolean() = true
fun getInt(): Int {
return 1
}
fun getString() = "Hello"
fun getLong() = 1L
fun getFloat() = 1.0f
fun getMember() = Member("fightnyy")
fun saveMemberFromDB(): Member {
return memberRepository.save(Member("fightnyy"))
}
}
// MockTest.kt
@SpringBootTest
@TestConstructor(autowireMode = TestConstructor.AutowireMode.ALL)
class MockTest {
val paymentService = mockk<PaymentService>(relaxed = true)
@Test
@DisplayName("Mock Test")
fun testLong(): Any {
every { memberRepository.save(any()) } returns Member("Nice")
println("result of Boolean : " + paymentService.getBoolean()) // false
println("result of Long! : " + paymentService.getLong()) // 0
println("result of Int : " + paymentService.getInt()) // 0
println("result of String : " + paymentService.getString()) // ""
println("result of String is same as empty? : " + paymentService.getString().isEmpty()) // true
println("result of Float : " + paymentService.getFloat()) // 0.0
println("result of Member : " + paymentService.getMember()) // Member(child of #2#4)
println("result of Member from DB : " + paymentService.saveMemberFromDB()) // Member(child of #2#5)
// 여기서 반환되는 Member의 값은 name = "", id = 0, deleted_at = "" 입니다.
}
}
- relaxed = true 옵션을 주게 되면 primitive 값들은 모두 기본값(0, false, "")을 반환하게 됩니다. 또한 클래스의 경우에는 chained mocks 리턴됩니다.(Member(child of #2#4) 같은 형식인데 클래스 내부 primitive 값들은 모두 기본값들을 반환합니다.)
- 만약 relaxed = true 옵션을 주지 않게 되면 어떤일이 벌어질까요?
- no answer found for: ...... 와 같은 형식의 에러 로그로 반환됩니다. 즉 목킹은 했는데 해당 목킹에 반환 값을 적용해주지 않았다는 의미입니다.
relaxUnitFun = true
- 해당 옵션은 Unit 으로 반환되는 함수들만 목킹합니다. 위의 paymentService 에 함수를 하나 추가해보겠습니다.
- 해당 함수는 relaxUnitFun = true 옵션을 줘도 되고 relaxed = true 옵션을 줘도 테스트가 통과하지만, 어떠한 파라미터도 주지 않은 경우는 다시 no answer found for: ....... 로그가 나옵니다.
- relaxUnitFun 은 반환타입이 Unit 인(즉, 함수가 아무것도 반환되지 않는 경우) 함수만 테스트에 모킹된 것처럼 동작합니다.
@Service class PaymentService(
private val memberRepository: MemberRepository)
){
// ... fun unitFunction(): Unit { println("unitFunction") }
}