티스토리 뷰

들어가며

  • Test Case를 작성하다 보면 테스트 하고자 하는 로직에 대해서 검증 로직과는 상관 없는 Extension Function 에 대해서 Mocking 을 해야 할 때가 있습니다.
    • 저의 경우에는 확장 함수를 주로 아래와 같은 Converting 의 목적(DTO -> VO, VO -> Entity, VO -> DTO 등)으로 사용하고 있었는데요
fun Context.toResult(): Result {
    /**
     * Convert Code ...
     *
     * return Result(
     *      name = title
     *      content = title + content
     *      code = resultCode.name
     *      reason = resultCode.reason
     *      subject = content
     *      ETC ....
     * )
     */
}
  • 핵심 로직에 대해서 검증을 하는데 있어서 확장함수에 대해서는 Mocking 을 해도 상관 없는 경우가 많습니다. 
  • Data Model 이 간단하다면 크게 문제될 건 없지만 복잡한 경우에는 Test Data 를 만드는데 피로도가 큽니다. 

방법

  • 코틀린 Mocking 라이브러리 mockk 를 이용하여 확장 함수를 Mocking 하는 방법을 알아보겠습니다.
  • 예제로는 간단하게 두 data 클래스간 변환을 수행하는 확장 함수가 있고 이 함수를 Mocking 해보겠습니다. 
//Exetensions.kt
package com.jinseong.mockk

data class Input(
    val title: String,
    val content: String
)

data class Output(
    val title: String,
    val content: String
)

fun Input.toOutput(title: String): Output {
    return Output(title, title)
}

 

 

  • mockk의  mockkStatic() 함수를 이용하여 파라미터로 해당 확장함수의 Full Path (패키지 경로 + 파일의 컴파일된 Class 명)을 넣어주면 됩니다.
    • 위 확장 함수의 패키지 경로가 `com.jinseong.mockk` 이고 위 파일이 컴파일 되었을 때 `ExtentionsKt` 라는 클래스가 됩니다. 
    • 그 이유에 대해서는 아래에서 더 자세히 알아보겠습니다.
  • 그 이후 일반적인 function mocking 방식으로 mocking 을 해주면 됩니다.  
class ExtensionTest {
    @Test
    fun `Extension Function Mocking 테스트`() {
        //given
        mockkStatic("com.jinseong.mockk.ExtensionsKt")
        
        val input = mockk<Input>()
        every { input.toOutput(any()) } returns Output("title", "content")

        //when
        val output = input.toOutput("sss")

        //then
        expectThat(output.title) isEqualTo "title"
        expectThat(output.content) isEqualTo "content"
    }
}

 

  • 위 함장 함수를 컴파일 하여 Java Code 형태로 디컴파일 하여 보게 되면 아래와 같은 형태가 됩니다. 
    • 코틀린의 확장 함수는 내부적으로는 클래스 내의 static function 으로 실행이 되는 것을 알 수가 있습니다. 
  • 그리하여 위 확장 함수의 Full Path 는 패키지명 + 컴파일 Class명 이 되는 것이죠. 
// ExtensionsKt.java
package com.jinseong.mockk;

import kotlin.Metadata;
import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;

@Metadata(
   mv = {1, 5, 1},
   k = 2,
   d1 = {"\u0000\u0012\n\u0000\n\u0002\u0018\u0002\n\u0002\u0018\u0002\n\u0000\n\u0002\u0010\u000e\n\u0000\u001a\u0012\u0010\u0000\u001a\u00020\u0001*\u00020\u00022\u0006\u0010\u0003\u001a\u00020\u0004¨\u0006\u0005"},
   d2 = {"toOutput", "Lcom/jinseong/mockk/Output;", "Lcom/jinseong/mockk/Input;", "title", "", "KotlinPlayGround"}
)
public final class ExtensionsKt {
   @NotNull
   public static final Output toOutput(@NotNull Input $this$toOutput, @NotNull String title) {
      Intrinsics.checkNotNullParameter($this$toOutput, "$this$toOutput");
      Intrinsics.checkNotNullParameter(title, "title");
      return new Output(title, title);
   }
}

관련글

 

 

[kotlin] MockK 사용시 Multiple Method Call Verification 방법

들어가며 테스트 코드를 작성하는 중 mock class에 대하여 verify를 사용할 일이 있었는데 한 메서드에 대해서 여러번 호출을 하고 검증시에 각각의 호출에 대한 Parameter 를 검증하고자 했다. 아래와

jinseongsoft.tistory.com

 

 

반응형
댓글