2022년 9월 11일 일요일

Mockk

Mockk

MockK ( with Kotlin )

mockk.io 공식사이트
최근 kotlin+ TDD 위주로 개발하는 경험을 하게되어 어떤 라이브러리를 쓰나 했더니 MockK를 쓰고있었다. Mokito처럼 어노테이션을 이용하여 목업을 할수 있어서 Mokito사용하라면 금방익숙해질수 있다.
어노테이션이나 함수들도 비교적 직관적으로 되어 있어서 테스트코드를 읽다보면 대충 어떤 상황인지 쉽게 파악알수 있다.

자주사용하는 키워드

  • mockk<객체타입이>() : 지정된 타입의 클래스를 목업으로 하는 목업객체를 만든다. (@MockK 어노테이션으로 해도된다)
  • every{} : {}안에 지정된 블럭이 테스트중에 실행된다면 아래의 return값을 돌려준다.
  • returns : 지정된 객체(값)를 every 블럭이 실행될때마다 돌려준다.
  • answers{} : returns가 한개의 객체만 리턴한다면, answers는 실행블럭(여러실행함수들이 담긴)을 리턴할수 있다.
  • verify{} : mockk로 지정한 객체의 특정함수, 속성등이 호출되었는지 검증한다. verifySequence,verifyOrder 를 사용하면 함수가 지정된 순서대로 호출되었는지도 검증할수있다.
  • justRun{} : 단지 어떤 함수를 목업형태로 실행하고 싶을때 사용한다.(kotlin Unit값을 리턴한다.)
  • spyk<객체타입> () : 객체를 Reflection한 목업객체를 만든다. 이때 원본 객체의 프로퍼티등도 직접 값을 바꿀수 있다.
  • any() : every내에서 사용하는 목업함수의 인자를 any, 즉 아무값이나 받았다고 가정한다. 즉 어떤 함수에 인자값이 뭐가 오든간에 라는 의미이다. allAny()도 있는데 인자의 개수에 상관없이 모두 any로 취급해준다.
  • relaxed = true : 목업객체나 리턴값 또는 함수인자에 이것을 지정하면, 목업객체(또는 함수)의 모든 응답은 객체 (또는 함수)자신의 리턴값을 리턴할수 있도록 여유(relax)를 준다. 따라서 목업된 객체의 함수들이 실행될때 answer 가 지정안되었다는 에러를 회피할수있다.
  • slot-capture : 슬럿은 말그대로 무언가 담을 그릇이고, 캡춰는 슬롯에 값이 담길때 그값을 잡아주는 역활을 한다. every 에서 함수를 실행시 특정 인자값을 함수에 전달(이때 캡춰한다)해서 그 값을 다시 return(answer) 에서 사용하고자 할때 slot-capture를 사용한다. 슬럿은 함수의 인자형태에 맞게 미리 변수로 선언되어있어야한다.

코틀린의 코루틴을 위한 함수도 제공한다.
coEvery, coVerify, coMatch, coAssert, coRun, coAnswers or coInvoke

@Test
fun 공홈샘플테스트코드() {
    // arrange
	val car = mockk<Car>()  // Car를 목업객체로 한다.
	val slot = slot<String>() // 슬럿을 만들어 둔다.
	every { car.drive(Direction.NORTH) } returns Outcome.OK // 목업된 객체의 drive함수가 실행되면 Outcome.OK 가 리턴된다. 물론 drive함수의 리턴값과 같은 형식이어야한다. 
	every { car.fly(any()) } returns mockk(relexed = true) // fly 함수는 어떤 리턴값이라도 검증에는 상관없다.
	every { car.rider(person = capture(slot) } returns "${slot.captured}가 타고있어" // slot-capture 함수를 이용해서 every의 rider를 실행할때 넘겨준 인자값을 결과값에 활용할 수있다.
	
	// act
	val result = car.drive(Direction.NORTH) // 목업객체의 drive를 실행했다.
	car.fly("비행기냐?") 
	val result2 = car.rider(person = "태발")
	
	// assert
	verify { car.drive(Direction.NORTH) } // car.drive(Direction.NORTH) 형태로 출력이 되었는가를 검사한다. 호출이 안되었더라면 failed가 된다.
	verify { car.fly(any()) }
	verify { car.rider(person = "태발") }
	
	confirmVerified(car)  // 목업객체의 every로 지정된 함수들이 모두 불리고 verify되었는지 재차 확인한다. 하나라도 verify 되지 않는 항목이 있다면 failed가 된다.
	assertEquals(result, Outcome.OK) // 예상값이 일치하는지 확인한다.
	assertEquals(result2, "태발가 타고있어") // 예상값이 일치하는지 확인한다.
}

라이브러리 추가

라이브러리추가는 Gradle에
testImplementation “io.mockk:mockk:{version}”
(안드로이드라면 이것도 추가)androidTestImplementation “io.mockk:mockk-android:{version}”
하면 테스트코드에 mockk를 사용할수 있다.

0 comments:

댓글 쓰기