Kotlin

MockKInjects 및 Lateinit 사용을 통한 Kotlin 테스트 이슈 해결하기

mayleaf 2023. 12. 13. 00:24

글을 쓰게 된 이유

이번 블로그 글에서는 Kotlin 테스트를 진행하면서, 특히 MockKInjects를 사용하면서 마주친 이슈를 공유하려 합니다. 이 문제는 테스트 클래스 생성자의 실행과 Injectmock에서 발생하는 버그와 관련이 있습니다. 디버깅하면서 봤던 코드들을 공유하면 다른 분들이 보기에 좋겠다 생각이 들어서 공유하기 위해 글을 씁니다.

문제 상황

MockKInjects를 작업하는 동안 테스트 클래스 생성자를 호출하면 Injectmock와 관련된 오류가 발생하는 걸 봤습니다. 오류 메시지는 다음과 같았습니다:

No ParameterResolver registered for parameter [%s] in %s [%s].

injectmocks에 주입해줄 파라미터들을 못찾는 이슈였는데, 저같은 경우는 Service에 주입되어야하는 Webclient와 repository를 못찾는 상황이었습니다.

초기 해결 방안:
이 문제를 해결하기 위해 저는 MockInject를 달아둔 프로퍼티만 생성자에서 lateinit으로 초기화하도록 변경했습니다. 이 변경으로 테스트가 성공적으로 실행되었고, 이는 MockInjects 초기화 방식과 관련된 문제라는 가설에 힘을 실어주는 것처럼 보였습니다.

해결 방안 확장:
초기 성공에 힘입어, 저는 모든 인스턴스에 대해 lateinit 수정을 적용해보기로 했습니다. 어차피 이상하면 깃으로 되돌리면 되니까요 :) 다행히 이 변경으로도 테스트가 원활하게 실행되었습니다. 이 실험은 초기화 과정이 문제의 근본 원인임을 더욱 확실히 해주었습니다.

문제 조사 확대:

테스트코드를 더 깊이 조사를 진행하면서, 문제의 원인을 다음 코드 라인에서 찾을 수 있었습니다:

기존에 모두 생성자로 초기화하던 때에는

invokeTestClassConstructor

이라는 함수에서 ExtensionContext를 통해서 주입을 받았는데, 이때 Mockk를 달아둔 프로퍼티의 목업들은 잘 주입되지만 InjectMocks를 달아둔 프로퍼티에 목업들을 조립해서 넣어주는 로직이 부재함을 알게 되었다.

invokeTestInstancePostProcessors(instances.getInnermostInstance(), registry, extensionContext);

그래서 lateinit으로 초기화하기로 된 목업들은 어떻게 채워졌을까 하고 보니, invokeTestClassConstructor를 호출 한 뒤에는 위 함수를 호출하고 있었다. 디버깅을 해보고 스택을 위로 다시 뒤져가면서 보다보니까 이 단계에서 lateinit 속성들이 채워지는게 명확해졌습니다. 이렇게 lateinit 속성을 채워넣던 과정은 PostProcessor가 모든 확장 기능을 처리하면서 이루어졌는데, 이 중 MockKExtension이 초기화 필드를 담당했습니다.
관련 코드는 다음과 같습니다:

override fun postProcessTestInstance(testInstance: Any, context: ExtensionContext) {
    MockKAnnotations.init(testInstance)
}

이 메서드는 postProcessTestInstance 인터페이스를 통해 호출되었고, Extension들은 모두 이렇게 인터페이스를 통해서 호출되는 구조라는 것을 알 수 있었습니다. 이 MockkExtension의 후처리 함수는 모든 lateinit 속성이 적절히 설정되도록 보장했습니다.

결론:
이 Kotlin 테스트 이슈에 대한 조사를 통해 초기화 과정이 MockKInjects를 작업할 때 얼마나 중요한지를 보여주었습니다. 주입하는 코드를 선호해서 이렇게 테스트 코드도 주입하는 식으로 작성을 시작했지만, 이렇게 테스트코드의 경우 전반적으로 lateinit을 적용하는 것이 효과적인 해결책이라는 생각이 들었습니다. 생성자 주입과 필드주입을 왔다갔다하는 것보다는 lateinit으로 모두 통일하는게 프로그래머의 고민을 덜수 있는 방법이라는 생각이 들었고, 유사하게 java 코드에서도 @autowired 필드주입을 통해서 문제를 해결하는게 일관성있는 테스트 코드 작성에 도움이 되겠다는 생각이 들었다.

'Kotlin' 카테고리의 다른 글

테스트 하기 좋은 코드, 좋은 테스트 코드  (0) 2024.01.15
IR compiler란?  (0) 2024.01.04
Error Stubbing 하기  (0) 2023.12.21
코틀린 스프링을 사용하는 이유  (0) 2023.11.20
코루틴이란?  (0) 2023.10.23