[SpringBoot] MockK로 단위테스트하기

tkppp·2022년 3월 24일
2

SpringBoot with Kotlin

목록 보기
11/12

문제 발생

지금까지 Kotlin + JUnit5 + Mockito 를 사용하여 단위테스트를 작성하였다. MockitoKotlin 을 같이 쓰기엔 불편한점이 있긴했지만 어쨋든 되긴하니 사용하고 있었다.

하지만 테스트 중에 repository.findByIdOrNull() 을 스텁하려하니 NPE 에러가 발생했다.

에러 로그

cannot be returned by findById()
findById() should return Optional

분명 findByIdOrNull 을 스텁했는데 findById() 는 Optional 객체를 반환해야한다는 에러 로그는 이해하기 힘들다.

구글링을 해보니 Mockito 는 정적 메소드에 대해서는 스텁할 수 없다고 한다. findByIdOrNull 는 코틀린에서 정의된 확장함수 이기 때문에 자바 코드로 디컴파일시 정적 메소드이기 때문에 에러가 발생한 것 같다.

이 문제를 해결하기 위해 findById 메소드를 사용하도록 코드를 바꾸는 것은 주객전도라 생각되어 모킹 프레임워크를 Mockito 에서 코틀린 프로젝트인 MockK 로 변경했다.

사용법

Extenstion

@ExtendWith(MockKExtension::class)
class TestClass {
	...
}

MockK를 사용하기 위해서는 MockKExtension 확장 기능을 추가해야한다.

Mock

목 객체를 생성하는 것은 Mockito와 크게 다르지 않다.

// Mockito Mock
val mock1 = mock(MockClass::class.java)

// MockK Mock
val mock = mockk<MockClass>()

Stub

// stub
every { mock.method() } returns "OK"
every { mock.methodWithArgs(any()) } returns "OK"

// mockito stub
`when`(mock.method()).thenReturn("OK")
`when`(mock.methodWithArgs(anyString())).thenReturn("OK")

stubbing 은 every 메소드를 사용한다. 유의할 점은 Mockito는 목 객체의 메소드를 stub 하지 않고 사용하면 null을 반환했지만 MockK 객체는 에러가 발생한다.

이것을 방지하려면 목 객체 생성시 relax 옵션으로 기본값을 설정해 RelaxedMock으로 만들어야 한다.

val mock = mockk<MockClass>(relax=true)

mock.method() // true 반환

Verify

목 객체의 함수 호출 여부 검사는 verify 메소드를 사용한다.

public fun verify(
    ordering: Ordering,
    inverse: Boolean,
    atLeast: Int,
    atMost: Int,
    exactly: Int,
    timeout: Long,
    verifyBlock: MockKVerificationScope.() -> Unit
): Unit

// 정확히 한번 실행
verify(exactly = 1) { mock.method(1) }

// 1000ms 내 실행
verify(timeout = 1000L) { mock.method(1) }

@MockBean, @SpyBean

MockkMockBean, SpyBean 과 같은 기능을 제공하지 않는다. 따로 사용하고 싶다면 Ninja-Squad/springmockk 의존성을 추가하고 @MockkBean, @SpykBean 어노테이션을 사용해야 한다.

참조

코틀린 mock 프레임워크 MockK 소개
Kotlin에서 mock 테스트 하기
https://techblog.woowahan.com/5825/

0개의 댓글