lannstark 2022. 5. 23. 22:02

https://mockk.io/

 

MockK

Provides DSL to mock behavior. Built from zero to fit Kotlin language. Supports named parameters, object mocks, coroutines and extension function mocking

mockk.io

 

mock 객체 생성하기

val domainRepository = mockk<DomainRepository>()

Argument Matching 사용하기

특정 객체에 expected answer를 부여할때 파라미터를 지정해주어야 한다. matcher는 다음과 같은 느낌으로 동작한다

// 들어오는 파라미터가 1L 일때만 cycle을 반환
every { domainRepository.findById(1L) } returns Optional.of(cycle)

// 어떤 파라미터가 들어오더라도 cycle을 반환
every { domainRepository.findById(any()) } returns Optional.of(cycle)

// 3 이하의 파라미터가 들어올때만 cycle을 반환
every { domainRepository.findById(less(3)) } returns Optional.of(cycle)

사용할 수 있는 전체 matcher 는 https://mockk.io/#matchers 에서 확인할 수 있다.

Expected Answer 사용하기

  • returns : 특정 method가 특정한 값을 반환하도록 한다 (위의 예시 참고)
  • returnsMany : 여러번 호출될때마다 순차적으로 다음 element를 반환하다록 한다
every { domainRepository.findById(1L) } returnsMany listOf(Optional.of(domain), Optinoal.of(domain))

returnsMany 대신 andThen 을 사용할 수도 있다.

every { mock1.call(5) } returns 1 andThen 2 andThen 3

throws는 Exception을 내게 해주며, just Runs는 아무것도 하지 않음을 의미한다 (Mock 객체를 생성할때 파라미터에 따라 설정되지 않은 method가 호출되면 런타임 에러가 날 수 있는데 이럴때 just Runs를 쓸 수도 있다)

every { mock1.call(5) } throws RuntimeException("error happened")

every { mock1.callReturningUnit(5) } just Runs

answers 는 정답을 반환하는 커스텀 람다 함수를 작성할 수 있게 해준다

every { mock1.call(5) } answers { arg<Int>(0) + 5 }

검증하기

mocking은 행위를 검증하기 위해 사용되는 기술인만큼, 행위 검증을 위한 기능들이 다양하게 존재한다.

대표적으로는 메소드의 호출 여부를 검증할 수 있다.

// mock1.call(5) 가 한 번 이상 호출되었는지 검증
verify { mock1.call(5) }

// mock.call(5)가 5번 이상 7번 이하로 호출되었는지 검증
verify(atLeast = 5, atMost = 7) { 
  mock1.call(5)
}

// mock1.call(5)가 정확히 한 번 호출되었는지 검증
verify(exactly = 5) { 
  mock1.call(5)
}

// mock1과의 상호작용이 전혀 없었는지를 검증
verify { 
  mock1 wasNot Called 
}

또한 순서를 검증할 수도 있다.

// mock.call(1) -> mock.call(2) -> mock.call(3) 순서로 '정확히' 호출되었고 그 사이 다른 호출이 없었음을 검증
verifySequence {
  mock1.call(1)
  mock1.call(2)
  mock1.call(3)
}

// mock1.call(1)이 mock.call(3) 보다 먼저 호출되었음을 검증
verifyOrder {
  mock1.call(1)
  mock1.call(3)
}