ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Mockk(relaxed = true) 는?
    언어/Kotlin 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")   } 
     }

    '언어 > Kotlin' 카테고리의 다른 글

    Kotlin safe call  (0) 2022.11.29
    Kotlin 에 대해서 알게 된 것들  (0) 2022.10.11

    댓글