Mockk 는 “mocking library for Kotlin” 이다. 간단한 사용법을 정리해보자.
Install
우선, 시작하기 앞서 dependency 를 추가해보자.
for gradle:
1
| testImplementation("io.mockk:mockk:{version}")
|
for maven:
1 2 3 4 5 6
| <dependency> <groupId>io.mockk</groupId> <artifactId>mockk</artifactId> <version>{version}</version> <scope>test</scope> </dependency>
|
Simple Example
mockk 를 활용한 간단한 테스트 코드를 작성해보자.
1 2 3 4 5 6 7 8 9 10 11 12 13
| @Test fun `sum`() { val additionCalculator = mockk<AdditionCalculator>() every { additionCalculator.calculate(1, 3) } returns 4
val result = additionCalculator.calculate(1, 3)
verify { additionCalculator.calculate(1, 3) } assertEquals(4, result) }
|
위 코드에서 사용된 mockk functions 를 정리하자.
- mockk: mock 객체를 생성
- every: 어떻게 동작을 해야하는지 정의
- verify: 호출 여부 검증
Annotations
mockk 에서 지원하는 Annotations 을 활용하면, 테스트 코드를 더 쉽게 작성할 수 있다.
@MockK
@MockK 를 사용해서 mock 객체를 쉽게 생성할 수 있다.
JUnit5 기반이라면, MockKExtension 을 사용해서 mock 객체를 초기화할 수 있다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| @ExtendWith(MockKExtension::class) class MockKAnnotationTest {
@MockK lateinit var sumCalculator: SumCalculator
@Test fun sum() { every { sumCalculator.calculate(1, 3) } returns 4
val result = sumCalculator.calculate(1, 3)
assertEquals(4, result) } }
|
test function 파라미터에 @MockK 를 바로 사용할 수도 있다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| @ExtendWith(MockKExtension::class) class MockKAnnotationWithFunctionParameterTest {
@Test fun sum(@MockK sumCalculator: SumCalculator) { every { sumCalculator.calculate(1, 3) } returns 4
val result = sumCalculator.calculate(1, 3)
assertEquals(4, result) } }
|
@InjectMockKs
다른 클래스에 의존하는 클래스에 mock object 를 주입해서 mocking 하고 싶으면,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| class Calculator( private val additionCalculator: AdditionCalculator, private val subtractionCalculator: SubtractionCalculator ) { }
@ExtendWith(MockKExtension::class) class InjectMocksTest {
@MockK lateinit var additionCalculator: AdditionCalculator
@MockK lateinit var subtractionCalculator: SubtractionCalculator
@InjectMockKs lateinit var calculator: Calculator
@Test internal fun `inject mocks`() { val num1 = 1 val num2 = 2
every { additionCalculator.calculate(num1, num2) } returns 3 every { subtractionCalculator.calculate(num1, num2) } returns -1
val actualResult = calculator.calculate(num1, num2)
val expectedResult = CalculationResult( addition = 3, subtraction = -1 ) assertEquals(expectedResult, actualResult) } }
|
Relaxed Mock
mock 객체가 어떤 동작을 해야하는지 정의하지말아보자.
1 2 3 4 5 6 7 8 9 10 11
| @Test fun `not relaxed`() { val additionCalculator = mockk<AdditionCalculator>()
val result = additionCalculator.calculate(1, 2)
assertEquals(3, result) }
|
“no answer found for: AdditionCalculator(#1).calculate(1, 2)” 메세지로 에러가 발생한다.
stubbing 을 할 때, 기대하는 특정 행동에 대한 정의를 하고 싶지 않으면 relaxed mocking 을 하자.
1 2 3 4 5 6 7 8 9 10 11
| @Test fun `relaxed`() { val additionCalculator = mockk<AdditionCalculator>(relaxed = true)
val result = additionCalculator.calculate(1, 2)
assertEquals(0, result) }
|