Kotlin MockK 사용법 (공식 문서 번역)

MockK는 테스트 코드를 작성하기 위한 코틀린 Mock 라이브러리이다. 이 문서는 공식 문서를 한국어로 변역하였다.

시작하기

MockK는 테스트 코드를 작성하기 위한 코틀린 Mock 라이브러리이다. 이 문서는 공식 문서를 한국어로 번역한 것이다.

설치

시작하기 위하여 필요한 것은 MockK 라이브러리에 종속성을 추가하는 것이다.

접근 명령
Gradle testImplementation "io.mockk:mockk:{version}"
Gradle (Kotlin DSL) testImplementation("io.mockk:mockk:{version}")
Maven <dependency> <groupId>io.mockk</groupId> <artifactId>mockk</artifactId> <version>{version}</version> <scope>test</scope> </dependency>
Unit testImplementation "io.mockk:mockk:{version}"
Instrumented androidTestImplementation "io.mockk:mockk-android:{version}"
Common multiplatform testImplementation "io.mockk:mockk-common:{version}"

{version}은 다음 버전에 해당한다.

  • Kotlin 1.3+ 및 Coroutines 1.0+ 버전
  • Kotlin 1.2 호환 버전

DSL 예제

가장 간단한 예제이다. 기본적으로 모의 객체는 엄격하므로 몇 가지 동작을 제공해야 한다.

val car = mockk<Car>()

every { car.drive(Direction.NORTH) } returns Outcome.OK

car.drive(Direction.NORTH) // returns OK

verify { car.drive(Direction.NORTH) }

confirmVerified(car)

어노테이션(Annotations)

어노테이션을 사용하여 모의 객체의 생성을 간소화할 수 있다.

class TrafficSystem {
  lateinit var car1: Car

  lateinit var car2: Car

  lateinit var car3: Car
}

class CarTest {
  @MockK
  lateinit var car1: Car

  @RelaxedMockK
  lateinit var car2: Car

  @MockK(relaxUnitFun = true)
  lateinit var car3: Car

  @SpyK
  var car4 = Car()

  @InjectMockKs
  var trafficSystem = TrafficSystem()

  @Before
  fun setUp() = MockKAnnotations.init(this, relaxUnitFun = true) // 모들 모형에 relaxUnitFun을 켜둔다.

  @Test
  fun calculateAddsValues1() {
      // ... use car1, car2, car3 and car4
  }
}

인젝션는 먼저 속성을 이름으로 조합하고 다음 클래스 또는 수퍼 클래스에 일치한다. 사용자에 대한 lookupType 매개 변수를 확인한다.

private으로 적용되는 경우에도 속성이 주입된다. 주입 생성자는 인수의 최대에서 최소까지 선택된다.

기본적으로 @InjectMockKslateinit var 또는 할당되지 않은 var만을 삽입한다. 이를 변경하려면 overrideValues = true를 사용한다. 이것은 이미 어떤 방법으로 초기화되는 경우에도 값을 할당한다. val를 주입하려면 injectImmutable = true를 사용한다. 짧은 형식의 경우, 디폴트로로 @InjectMockKs와 같은 동작을 하는 @OverrideMockKs을 사용하지만, 이 2개의 플래그를 선택한다.

JUnit5

JUnit5은 MockKExtension을 사용하여 모의를 초기화 할 수 있다.

@ExtendWith(MockKExtension::class)
class CarTest {
  @MockK
  lateinit var car1: Car

  @RelaxedMockK
  lateinit var car2: Car

  @MockK(relaxUnitFun = true)
  lateinit var car3: Car

  @SpyK
  var car4 = Car()

  @Test
  fun calculateAddsValues1() {
      // ... use car1, car2, car3 and car4
  }
}

또한 테스트 함수의 매개 변수에 @MockK@RelaxedMockK을 사용할 수 있는 가능성을 추가한다.

@Test
fun calculateAddsValues1(@MockK car1: Car, @RelaxedMockK car2: Car) {
  // ... use car1 and car2
}

Spy

스파이 모의과 실제 객체를 혼합 할 수 있다.

val car = spyk(Car()) // 또는 spyk<Car>()으로 디폴트 생성자를 호출한다.

car.drive(Direction.NORTH) // Car가 반환하는 실제 함수를 반환한다.

verify { car.drive(Direction.NORTH) }

confirmVerified(car)

참고 : 스파이 객체는 전달된 객체의 복사본이다.

Relaxed mock

relaxed mock모든 함수에 대해 간단한 값을 반환 모의이다. 따라서 각 케이스의 동작 지정을 생략하면서 필요한 것을 스텁 할 수 있다. 참조 형의 경우, 연쇄 모의가 반환된다.

val car = mockk<Car>(relaxed = true)

car.drive(Direction.NORTH) // returns null

verify { car.drive(Direction.NORTH) }

confirmVerified(car)

참고 : relaxed mock를 사용하는 경우, 반환 값이 제네릭이 잘 작동하지 않습니다. 일반적으로이 경우 클래스 캐스트 예외가 throw 된다. 반환 값이 제네릭이면 스텁을 수동으로 지정해야 한다.

해결 방법 :

val func = mockk<() -> Car>(relaxed = true) // 이 경우 invoke 함수는 반환 값에 제네릭이 있다

//이 라인은 해결 방법이다. 이 행이 없으면`relaxed mock`는 다음 줄에 클래스 캐스트 예외를 throw 한다
every { func() } returns Car() // 또는 예를 들어 mockk()을 반환 할 수 있다

func()

Unit을 반환하는 함수의 Relaxed mock (Mock relaxed for functions returning Unit)

Unit을 반환하는 함수를 Relaxed mock으로 하고 싶다면 mockk 함수, @MockK 어노테이션 또는 MockKAnntations.init 함수의 인수로 relaxUnitFun = true을 사용할 수 있다.

mockk 함수 :

mockk<MockCls>(relaxUnitFun = true)

@MockK 어노테이션 :

@MockK(relaxUnitFun = true)
lateinit var mock1: RurfMockCls
init {
    MockKAnnotations.init(this)
}

MockKAnntations.init 함수 :

@MockK
lateinit var mock2: RurfMockCls
init {
    MockKAnnotations.init(this, relaxUnitFun = true)
}

객체 모형 (Object mocks)

객체는 다음과 같은 방법으로 모의로 변환 할 수 있다.

object MockObj {
  fun add(a: Int, b: Int) = a + b
}

mockkObject(MockObj) // 모의 객체에 적용한다

assertEquals(3, MockObj.add(1, 2))

every { MockObj.add(1, 2) } returns 55

assertEquals(55, MockObj.add(1, 2))

취소는 unmockkAll 또는 unmockkObject를 사용한다.

@Before
fun beforeTests() {
    mockkObject(MockObj)
    every { MockObj.add(1,2) } returns 55
}

@Test
fun willUseMockBehaviour() {
    assertEquals(55, MockObj.add(1,2))
}

@After
fun afterTests() {
    unmockkAll()
    // or unmockkObject(MockObj)
}

Kotlin 언어의 제한에도 불구하고 테스트 로직에 필요한 경우 객체의 새 인스턴스를 만들 수 있다.

val newObjectMock = mockk<MockObj>()

클래스 모의 (Class mock)

때로는 어떤 클래스의 모의가 필요하다. 그런 경우에는 mockkClass을 사용한다.

val car = mockkClass(Car::class)

every { car.drive(Direction.NORTH) } returns Outcome.OK

car.drive(Direction.NORTH) // returns OK

verify { car.drive(Direction.NORTH) }

열거 모의 (Enumeration mocks)

열거 형은 mockkObject을 사용하여 모의 할 수 있다.

enum class Enumeration(val goodInt: Int) {
    CONSTANT(35),
    OTHER_CONSTANT(45);
}

mockkObject(Enumeration.CONSTANT)
every { Enumeration.CONSTANT.goodInt } returns 42
assertEquals(42, Enumeration.CONSTANT.goodInt)

생성자 모의 (Constructor mocks)

경우에 따라서는 특히 소유하지 않은 코드에서는 새로 만든 객체를 모의해야한다. 이를 위해 다음 구성이 제공된다.

class MockCls {
  fun add(a: Int, b: Int) = a + b
}

mockkConstructor(MockCls::class)

every { anyConstructed<MockCls>().add(1, 2) } returns 4

assertEquals(4, MockCls().add(1, 2)) // 새로운 객체가 생성되는 점에 유의하길 바란다

verify { anyConstructed<MockCls>().add(1, 2) }

기본적인 아이디어는 모의된 클래스의 생성자가 실행 된 직후에 객체 constructed mock가 될 것이다. 그런 모의 모의 동작은 anyConstructed<MockCls>()로 표시되는 특별한 prototype mock 연결된다. 이러한 prototype mock클래스 당 하나의 인스턴스가 있다. 통화 기록은 prototype mock하지만 발생한다. 함수가 지정되지 않은 경우 원래 함수가 실행된다.

부분 인수 매칭 (Partial argument matching)

보통 인수와 매칭 모두를 혼합 할 수 있다.

val car = mockk<Car>()

every { 
  car.recordTelemetry(
    speed = more(50),
    direction = Direction.NORTH, // 여기에 "eq()"가 사용되었다.
    lat = any(),
    long = any()
  )
} returns Outcome.RECORDED

obj.recordTelemetry(60, Direction.NORTH, 51.1377382, 17.0257142)

verify { obj.recordTelemetry(60, Direction.NORTH, 51.1377382, 17.0257142) }

confirmVerified(obj)

연쇄 호출 (Chained calls)

호출 체인을 스텁 할 수 있다.

val car = mockk<Car>()

every { car.door(DoorType.FRONT_LEFT).windowState() } returns WindowState.UP

car.door(DoorType.FRONT_LEFT) // Door 연쇄 모의를 반환한다
car.door(DoorType.FRONT_LEFT).windowState() // returns WindowState.UP

verify { car.door(DoorType.FRONT_LEFT).windowState() }

confirmVerified(car)

참고 : 함수의 반환 형식이 제네릭 인 경우 실제 형식에 대한 정보는 삭제됩니다. 연쇄 호출을 작동하려면 추가 정보가 필요한다. 대부분의 경우 프레임 워크는 캐스트 예외를 캐치하고 autohinting실행한다. 명시적으로 필요한 경우는 다음의 호출을 하기 전에 hint을 사용한다.

every { obj.op2(1, 2).hint(Int::class).op1(3, 4) } returns 5

계층적 모형 (Hierarchical mocking)

버전 1.9.1에서 모의 ​​계층에 체인 수 있다.

interface AddressBook {
    val contacts: List<Contact>
}

interface Contact {
    val name: String
    val telephone: String
    val address: Address
}

interface Address {
    val city: String
    val zip: String
}

val addressBook = mockk<AddressBook> {
    every { contacts } returns listOf(
        mockk {
            every { name } returns "John"
            every { telephone } returns "123-456-789"
            every { address.city } returns "New-York"
            every { address.zip } returns "123-45"
        },
        mockk {
            every { name } returns "Alex"
            every { telephone } returns "789-456-123"
            every { address } returns mockk {
                every { city } returns "Wroclaw"
                every { zip } returns "543-21"
            }
        }
    )
}

캡처 (Capturing)

CapturingSlot 또는 MutableList로 인수를 캡처 할 수 있다.

val car = mockk<Car>()

val slot = slot<Double>()
val list = mutableListOf<Double>()

every {
  obj.recordTelemetry(
    speed = capture(slot),
    direction = Direction.NORTH
  )
} answers {
  println(slot.captured)

  Outcome.RECORDED
}


every {
  obj.recordTelemetry(
    speed = capture(list),
    direction = Direction.SOUTH
  )
} answers {
  println(list.captured())

  Outcome.RECORDED
}

obj.recordTelemetry(speed = 15, direction = Direction.NORTH) // prints 15
obj.recordTelemetry(speed = 16, direction = Direction.SOUTH) // prints 16

verify(exactly = 2) { obj.recordTelemetry(speed = or(15, 16), direction = any()) }

confirmVerified(obj)

최소, 최대, 또는 정확한 횟수의 검증 (Verification atLeast, atMost or exactly times)

호출 카운트는 atLeast, atMost또는 exactly매개 변수에서 확인할 수 있다.

val car = mockk<Car>(relaxed = true)

car.accelerate(fromSpeed = 10, toSpeed = 20)
car.accelerate(fromSpeed = 10, toSpeed = 30)
car.accelerate(fromSpeed = 20, toSpeed = 30)

// 모든 통과한다
verify(atLeast = 3) { car.accelerate(allAny()) }
verify(atMost  = 2) { car.accelerate(fromSpeed = 10, toSpeed = or(20, 30)) }
verify(exactly = 1) { car.accelerate(fromSpeed = 10, toSpeed = 20) }
verify(exactly = 0) { car.accelerate(fromSpeed = 30, toSpeed = 10) } // 호출되지 않았음을 의미한다

confirmVerified(car)

검증 순서 (Verification order)

  • verifyAll순서를 확인하지 않고 모든 호출이 이루어 졌는지를 확인한다.
  • verifySequence는 지정된 순서로 호출이 이루어 졌는지를 확인한다.
  • verifyOrder호출이 특정 순서로 발생했는지 여부를 확인한다.
  • wasNot Called은 모의 또는 모의 목록이 전혀 호출되지 않았음을 확인한다.
class MockedClass {
    fun sum(a: Int, b: Int) = a + b
}

val obj = mockk<MockedClass>()
val slot = slot<Int>()

every {
    obj.sum(any(), capture(slot))
} answers {
    1 + firstArg<Int>() + slot.captured
}

obj.sum(1, 2) // returns 4
obj.sum(1, 3) // returns 5
obj.sum(2, 2) // returns 5

verifyAll {
    obj.sum(1, 3)
    obj.sum(1, 2)
    obj.sum(2, 2)
}

verifySequence {
    obj.sum(1, 2)
    obj.sum(1, 3)
    obj.sum(2, 2)
}

verifyOrder {
    obj.sum(1, 2)
    obj.sum(2, 2)
}

val obj2 = mockk<MockedClass>()
val obj3 = mockk<MockedClass>()
verify {
    listOf(obj2, obj3) wasNot Called
}

confirmVerified(obj)

검증 확인 (Verification confirmation)

verify... 구문에 의해 모든 호출이 검증된 것을 다시 확인하려면, confirmVerified을 사용할 수 있다.

confirmVerified(mock1, mock2)

이러한 검증 방법은 검증 된 모든 호출을 망라하고 있기 때문에, verifySequence 그리고 verifyAll을 사용하는 것은별로 의미가 없다.

몇 군데가 검증없이 남아있는 경우 예외를 throw 한다.

일부 호출은 이러한 확인에서 제외 될 수 있다. 자세한 내용은 다음 섹션을 확인한다.

val car = mockk<Car>()

every { car.drive(Direction.NORTH) } returns Outcome.OK
every { car.drive(Direction.SOUTH) } returns Outcome.OK

car.drive(Direction.NORTH) // returns OK
car.drive(Direction.SOUTH) // returns OK

verify {
    car.drive(Direction.SOUTH)
    car.drive(Direction.NORTH)
}

confirmVerified(car) // 모든 호출이 검증이 적용되었음을 확인한다

기록 제외 (Recording exclusions)

그다지 중요하지 않은 호출을 기록에서 제외하려면, excludeRecords를 사용할 수 있다.

excludeRecords { mock.operation(any(), 5) }

일치하는 모든 통화 기록에서 제외된다. 이것은 verifyAll, verifySequence, confirmVerified등의 포괄적인 검증을 사용하는 경우에 유용하다

val car = mockk<Car>()

every { car.drive(Direction.NORTH) } returns Outcome.OK
every { car.drive(Direction.SOUTH) } returns Outcome.OK

excludeRecords { car.drive(Direction.SOUTH) }

car.drive(Direction.NORTH) // returns OK
car.drive(Direction.SOUTH) // returns OK

verify {
    car.drive(Direction.NORTH)
}

confirmVerified(car) // car.drive(Direction.SOUTH)가 제외 된 때문에 car.drive(Direction.NORTH)에서만 확인할 수 있다.

확인 시간 (Verification timeout)

동시 작업을 확인하려면 timeout = xxx을 사용할 수 있다.

mockk<MockCls> {
    every { sum(1, 2) } returns 4

    Thread {
        Thread.sleep(2000)
        sum(1, 2)
    }.start()

    verify(timeout = 3000) { sum(1, 2) }
}

이는 검증을 통과하거나 시간 제한에 도달하거나 하나의 상태가 될 때까지 기다린다.

Unit을 반환 (Returning Unit)

함수가 Unit을 반환하는 경우는 just Runs를 사용할 수 있다.

class MockedClass {
    fun sum(a: Int, b: Int): Unit {
        println(a + b)
    }
}

val obj = mockk<MockedClass>()

every { obj.sum(any(), 3) } just Runs

obj.sum(1, 1)
obj.sum(1, 2)
obj.sum(1, 3)

verify {
    obj.sum(1, 1)
    obj.sum(1, 2)
    obj.sum(1, 3)
}

코루틴 (Coroutines)

코루틴을 모의하려면 지원 라이브러리에 다른 종속성을 추가해야 한다.

Gradle

testCompile "org.jetbrains.kotlinx:kotlinx-coroutines-core:x.x"

Maven

<dependency>
    <groupId>org.jetbrains.kotlinx</groupId>
    <artifactId>kotlinx-coroutines-core</artifactId>
    <version>x.x</version>
    <scope>test</scope>
</dependency>

다음은 coEvery, coVerify, coMatch, coAssert, coRun, coAnswers 또는 coInvoke를 사용하여 중단 함수를 모의로 할 수 있다.

val car = mockk<Car>()

coEvery { car.drive(Direction.NORTH) } returns Outcome.OK

car.drive(Direction.NORTH) // returns OK

coVerify { car.drive(Direction.NORTH) }

확장 기능 (Extension functions)

확장 함수는 세 가지 경우가 있다.

  • 전체 클래스 (class wide)
  • 전체 객체 (object wide)
  • 전체 모듈 (module wide)

객체와 클래스의 경우 일반적으로 모의하는 것만으로 확장 함수를 모의 할 수 있다.

data class Obj(val value: Int)

class Ext {
    fun Obj.extensionFunc() = value + 5
}

with(mockk<Ext>()) {
    every {
        Obj(5).extensionFunc()
    } returns 11

    assertEquals(11, Obj(5).extensionFunc())

    verify {
        Obj(5).extensionFunc()
    }
}

전체 모듈의 확장 기능을 모의하려면 모듈의 클래스 이름을 인수로 mockkStatic(...)로 빌드해야 한다. 예를 들어, pkg 패키지 모듈 File.kt"pkg.FileKt"으로 하면 된다.

data class Obj(val value: Int)

// File.kt("pkg" 패키지)로 선언되어 있습니다
fun Obj.extensionFunc() = value + 5

mockkStatic("pkg.FileKt")

every {
    Obj(5).extensionFunc()
} returns 11

assertEquals(11, Obj(5).extensionFunc())

verify {
    Obj(5).extensionFunc()
}

@JvmName를 사용하는 경우는 클래스 이름으로 지정한다.

KHttp.kt :

@file:JvmName("KHttp")

package khttp
// ... KHttp code 

테스트 코드 :

mockkStatic("khttp.KHttp")

확장 함수를 모의하기 위해 좀 더 자세히 알 필요가 있는 경우가 있다. 예를 들어, File.endsWith() 확장 기능에는 전혀 예측할 수 없는 classname이 있다.

mockkStatic("kotlin.io.FilesKt__UtilsKt")
every { File("abc").endsWith(any<String>()) } returns true
println(File("abc").endsWith("abc"))

이것은 예측 불가능한 표준 Kotlin 동작이다. [Tools]-> [Kotlin]->[Show Kotlin Bytecode]를 사용하거나 JAR 아카이브에서 .class 파일을 확인하여 이러한 이름을 검색한다.

가변 인수 (Varargs)

버전 1.9.1에서 더욱 확장된 가변 인수 처리가 가능하게 되었다.

    interface ClsWithManyMany {
        fun manyMany(vararg x: Any): Int
    }

    val obj = mockk<ClsWithManyMany>()

    every { obj.manyMany(5, 6, *varargAll { it == 7 }) } returns 3

    println(obj.manyMany(5, 6, 7)) // 3
    println(obj.manyMany(5, 6, 7, 7)) // 3
    println(obj.manyMany(5, 6, 7, 7, 7)) // 3

    every { obj.manyMany(5, 6, *anyVararg(), 7) } returns 4

    println(obj.manyMany(5, 6, 1, 7)) // 4
    println(obj.manyMany(5, 6, 2, 3, 7)) // 4
    println(obj.manyMany(5, 6, 4, 5, 6, 7)) // 4

    every { obj.manyMany(5, 6, *varargAny { nArgs > 5 }, 7) } returns 5

    println(obj.manyMany(5, 6, 4, 5, 6, 7)) // 5
    println(obj.manyMany(5, 6, 4, 5, 6, 7, 7)) // 5

    every {
        obj.manyMany(5, 6, *varargAny {
            if (position < 3) it == 3 else it == 4
        }, 7)
    } returns 6

    println(obj.manyMany(5, 6, 3, 4, 7)) // 6
    println(obj.manyMany(5, 6, 3, 4, 4, 7)) // 6

개인 함수의 모의 / 동적 호출 (Private functions mocking / dynamic calls)

개인 함수를 모의 할 필요가 있는 경우에는 동적 호출을 통해 할 수 있다.

class Car {
    fun drive() = accelerate()

    private fun accelerate() = "going faster"
}

val mock = spyk<Car>(recordPrivateCalls = true)

every { mock["accelerate"]() } returns "going not so fast"

assertEquals("going not so fast", mock.drive())

verifySequence {
    mock.drive()
    mock["accelerate"]()
}

개인 호출을 확인하는 경우는 recordPrivateCalls = truespyk를 작성해야 한다.

또한 자세한 구문은 같은 동적 호출과 함께 속성을 가져오고 설정할 수 있다.

val mock = spyk(Team(), recordPrivateCalls = true)

every { mock getProperty "speed" } returns 33
every { mock setProperty "acceleration" value less(5) } just runs
every { mock invokeReturnsUnit "privateMethod" } just runs
every { mock invoke "openDoor" withArguments listOf("left", "rear") } returns "OK"

verify { mock getProperty "speed" }
verify { mock setProperty "acceleration" value less(5) }
verify { mock invoke "openDoor" withArguments listOf("left", "rear") }

속성 백업 필드 (Property backing fields)

fieldValue를 통해 필드 백업 속성에 액세스하여 설정되는 값에 value 사용할 수 있다.

참고 : 다음 예제에서는 propertyType을 사용하여 fieldValue 형식을 지정한다. 이것은 겟타 유형을 자동으로 캡처 할 수 있기 때문에 필요한다. nullablePropertyType를 사용하여 null 허용 유형을 지정한다.

val mock = spyk(MockCls(), recordPrivateCalls = true)

every { mock.property } answers { fieldValue + 6 }
every { mock.property = any() } propertyType Int::class answers { fieldValue += value }
every { mock getProperty "property" } propertyType Int::class answers { fieldValue + 6 }
every { mock setProperty "property" value any<Int>() } propertyType Int::class answers  { fieldValue += value }
every {
    mock.property = any()
} propertyType Int::class answers {
    fieldValue = value + 1
} andThen {
    fieldValue = value - 1
}

여러 인터페이스 (Multiple interfaces)

인터페이스를 통해 추가 동작을 추가하고 이를 스텁화 한다.

val spy = spyk(System.out, moreInterfaces = Runnable::class)

spy.println(555)

every {
    (spy as Runnable).run()
} answers {
    (self as PrintStream).println("Run! Run! Run!")
}

val thread = Thread(spy as Runnable)
thread.start()
thread.join()

Mocking nothing

여기에 특별한 것은 아무것도 없다. Nothing을 반환하는 함수가 있는 경우 :

fun quit(status: Int): Nothing {
    exitProcess(status)
}

다음으로, 예를 들어, 예외를 작동으로 발생 할 수 있다.

every { quit(1) } throws Exception("this is a test")

매칭의 확장성 (Matcher extensibility)

아주 간단한 방법은 MockKMatcherScope 또는 MockKVerificationScope 함수에 연결하고 match 함수를 사용하여 새 매칭를 만드는 것이다.

fun MockKMatcherScope.seqEq(seq: Sequence<String>) = match<Sequence<String>> {
    it.toList() == seq.toList()
}

또한 Matcher 인터페이스를 구현하여 고급 매칭를 만들 수 있다.

설정 파일 (Settings file)

매개 변수를 전역으로 조정하려면 리소스 파일에서 일부 설정을 지정한다.

사용법 :

  1. 리소스 io/mockk/settings.properties파일을 만듭니다.
  2. 다음 옵션 중 하나를 입력한다.
relaxed=true|false
relaxUnitFun=true|false
recordPrivateCalls=true|false

DSL 테이블 (DSL tables)

DSL을 습득하는데 도움이 되는 몇 가지 표를 보여준다

최상위 함수 (Top level functions)

함수 설명
mockk<T>(...) 일반 모의한다.
spyk<T>() 기본 생성자를 사용하여 스파이를 구축한다.
spyk(obj) obj복사하여 스파이를 구축한다.
slot 캡처 슬롯을 만듭니다
every 스텁 블록을 시작한다.
coEvery 코루틴 스텁 블록을 시작한다.
verify 검증 블록을 시작한다.
coVerify 코루틴 검증 블록을 시작한다.
verifyAll 모든 호출을 포함한 검증 블록을 시작한다.
coVerifyAll 코루틴의 모든 호출을 포함한 검증 블록을 시작한다.
verifyOrder 순서를 확인하는 검증 블록을 시작한다.
coVerifyOrder 코루틴 순서를 확인하는 검증 블록을 시작한다.
verifySequence 모든 호출이 지정된 순서로 발생했는지 여부를 확인하는 검증 블록을 시작한다.
coVerifySequence 코루틴의 모든 호출이 지정된 순서로 발생했는지 여부를 확인하는 검증 블록을 시작한다.
excludeRecords 호출에서 일부 기록을 제외
confirmVerified 기록 된 모든 호출이 검증 된 것을 확인한다.
clearMocks 지정된 모의을 지운다.
registerInstanceFactory 특정 객체의 인스턴스화 방법을 다시 정의 할 수 있다
mockkClass 클래스를 매개 변수로 전달하여 일반 모의한다.
mockkObject 모든 객체를 객체의 모의하거나 이미 변환 된 경우 취소한다.
unmockkObject 객체 모형을 일반 객체로 되돌린다
mockkStatic 클래스에서 정적 모의하거나 이미 변환 된 경우 취소한다.
unmockkStatic 정적 모의을 정규 수업으로 되돌린다
clearStaticMockk 정적 모의을 지운다
mockkConstructor 생성자 모의 클래스에서 분리하거나 이미 변환 된 경우 취소한다.
unmockkConstructor 생성자 모의을 정규 수업으로 되돌린다
clearConstructorMockk 생성자의 모의를 지운다
unmockkAll 객체 모의 정적 모의 생성자 모의 안못쿠한다.
clearAllMocks 일반 모의 객체 모의 정적 모의 생성자 모의을 지운다

매칭 (Matchers)

기본적으로 간단한 인수 eq()를 사용하여 일치된다.

매칭 설명
any() 모든 인수와 일치한다.
allAny() 간단한 인수로 제공되는 매칭에 eq()대신 any()사용하는 특별한 매칭이다.
isNull() 값이 null인지 여부를 확인한다.
isNull(inverse=true) 값이 null 있는지 확인한다.
ofType(type) 값이 유형에 속하는지 여부를 확인한다.
match { it.startsWith("string") } 전달 된 술어를 통해 일치한다.
coMatch { it.startsWith("string") } 전달 된 코루틴 술어를 통해 일치한다.
matchNullable { it?.startsWith("string") } 전달 된 술어를 통해 null 허용 값과 일치한다.
coMatchNullable { it?.startsWith("string") } 전달 된 코루틴 술어를 통해 null 허용 값과 일치한다.
eq(value) 값이 deepEquals함수를 통해 제공된 값과 같으면 일치한다.
eq(value, inverse=true) 값이 deepEquals 함수를 통해 제공된 값과 같지 않으면 일치한다.
neq(value) 값이 deepEquals함수를 통해 제공된 값과 같지 않으면 일치한다.
refEq(value) 값이 참조 비교에 의해 제공된 값과 같으면 일치한다.
refEq(value, inverse=true) 값이 참조 비교에 의해 제공된 값과 같지 않으면 일치한다.
nrefEq(value) 값이 참조 비교에 의해 제공된 값과 같지 않으면 일치한다.
cmpEq(value) 값이 compareTo 함수에 제공된 값과 같으면 일치한다.
less(value) 값이 compareTo 함수에 지정된 값보다 작은 경우에 일치한다.
more(value) 값이 compareTo 함수에 제공된 값보다 큰 경우에 일치한다.
less(value, andEquals=true) 값이 compareTo 함수에 지정된 값 이하인 경우에 일치한다.
more(value, andEquals=true) 값이 compareTo함수에 지정된 값 이상인 경우에 일치한다.
range(from, to, fromInclusive=true, toInclusive=true) compareTo 함수를 통해 값이 범위 내에있는 경우에 일치한다.
and(left, right) 논리적으로 두 매칭를 결합한다.
or(left, right) 논리합에서 두 매칭를 결합한다.
not(matcher) 매칭을 해제한다.
capture(slot) CapturingSlot값을 캡처한다.
capture(mutableList) 값을 목록에 캡처한다.
captureNullable(mutableList) null 값과 함께 값을 목록에 캡처한다.
captureLambda() 람다를 캡처한다.
captureCoroutine() 코루틴를 캡처한다.
invoke(...) 일치하는 인수를 호출한다.
coInvoke(...) 코루틴 일치하는 인수를 호출한다.
hint(cls) 삭제 된 경우에 대비하여 다음의 반환 유형을 나타냅니다
anyVararg() 가변 인수의 모든 요소와 일치한다.
varargAny(matcher) 하나의 요소가 매칭에 일치하는 경우 일치한다.
varargAll(matcher) 모든 요소가 매칭에 일치하는 경우 일치한다.
any...Vararg() 가변 인수의 모든 요소와 일치한다. (기본 형식 별)
varargAny...(matcher) 하나의 요소가 매칭에 일치하는 경우 일치한다. (기본 형식 별)
varargAll...(matcher) 모든 요소가 매칭에 일치하는 경우 일치한다. (기본 형식 별)

검증 모드에서만 사용 가능한 특별한 매칭이 몇 가지 있다.

매칭 설명
withArg { code } 임의의 값과 일치하고 코드의 실행을 허용한다.
withNullableArg { code } null 값을 허용하는 값과 일치하고 코드의 실행을 허용한다.
coWithArg { code } 임의의 값과 일치하고 코 루틴 코드를 실행할 수 있다
coWithNullableArg { code } null 값을 허용하는 값과 일치하고 코 루틴 코드를 실행할 수 있다

유효성 체크 (Validators)

유효성 체크 설명
verify { mock.call() } 호출이 실행 된 것을 순서로 확인한다.
verify(inverse=true) { mock.call() } 호출이 실행되지 않은 것을 순서로 확인한다.
verify(atLeast=n) { mock.call() } 호출이 최소한 n 번 실행 된 것을 순서로 확인한다.
verify(atMost=n) { mock.call() } 호출이 최대 n 번 실행 된 것을 순서로 확인한다.
verify(exactly=n) { mock.call() } 호출이 정확히 n 번 실행 된 것을 순서로 확인한다.
verifyAll { mock.call1(); mock.call2() } 언급 된 모의에 지정된 호출 만 실행 된 것을 순서로 확인한다.
verifyOrder { mock.call1(); mock.call2() } 지정한 순서대로 호출이 차례로 이루어 졌는지 확인한다.
verifySequence { mock.call1(); mock.call2() } 언급 된 모의에 대해 지정된 일련의 호출 만이 수행되었음을 확인한다.
verify { mock wasNot Called } 모의가 호출되지 않았 음을 확인한다.
verify { listOf(mock1, mock2) wasNot Called } 모의 목록이 호출되지 않았 음을 확인한다.

응답 (Answers)

응답 후에 하나 이상의 추가 응답이 계속되는 경우가 있다.

도움말 설명
returns value 일치하는 호출이 지정된 값을 반환하도록 지정한다.
returnsMany list 일치하는 호출 목록에서 값을 반환 후속 호출이 다음의 요소를 반환하도록 지정한다.
throws ex 일치하는 호출이 예외를 슬로우하는 것을 지정한다.
answers { code } 일치하는 호출 answer scope을하는 코드 블록으로 응답하도록 지정한다.
coAnswers { code } 일치 한 호출 answer scope을 가진 코 루틴 코드 블록으로 응답하도록 지정한다.
answers answerObj 일치하는 호출 Answer 객체에 응답하도록 지정한다.
answers { nothing } 일치하는 호출이 null로 응답하도록 지정한다.
just Runs 일치하는 호출이 Unit을 반환하도록 지정한다. (null를 반환한다)
propertyType Class 지원 필드 접근 자 유형을 지정한다.
nullablePropertyType Class 지원 필드 접근의 형태를 null 허용 형식으로 지정한다.

추가 응답 (Additional answer)

결과적으로 생기는 각 호출에서 다음 응답을 반환, 마지막 값이 유지된다. 이것은 returnsMany의미와 비슷한다.

추가 도움말 설명
andThen value 일치하는 호출이 하나의 지정된 값을 반환하도록 지정한다.
andThenMany list 일치하는 호출 목록에서 값을 돌려 다음의 요소가 반환 될 때마다 반환하도록 지정한다.
andThenThrows ex 일치하는 호출이 예외를 슬로우하는 것을 지정한다.
andThen { code } 일치하는 호출 answer scope에서 범위 된 코드 블록에 응답하도록 지정한다.
coAndThen { code } 일치하는 호출 answer scope에서 범위 된 코 루틴 코드 블록으로 응답하도록 지정한다.
andThenAnswer answerObj 일치하는 호출 Answer 객체에 응답하도록 지정한다.
andThen { nothing } 일치하는 호출이 null로 응답하도록 지정한다.

응답 범위 (Answer scope)

매개 변수 설명
call 호출 및 매칭으로 구성된 호출 객체
invocation 호출 된 실제 함수에 대한 정보가 포함되어 있다
matcher 호출의 조합에 사용되는 매칭 대한 정보가 포함되어 있다
self 호출 된 객체를 참조한다.
method 호출 된 함수를 참조한다.
args 호출 인수를 참조한다.
nArgs 호출 인수의 수
arg(n) n 번째의 인수
firstArg() 첫 번째 인수
secondArg() 두 번째 인수
thirdArg() 셋째 인수
lastArg() 마지막 인수
captured() 목록으로 캡처 할 때 편리한 목록의 마지막 요소
lambda<...>().invoke() 캡처 된 람다를 호출
coroutine<...>().coInvoke() 캡처 된 코루틴를 호출
nothing 대답은 아무것도 돌려주지 않는 경우는 null 값
fieldValue 속성 백업 필드에 접근
fieldValueAny Any?형태를 가지는 속성 백업 필드에 접근
value 속성 백업 필드와 같은 형태로 캐스팅 된 값
valueAny Any?형태로 설정되어 있는 값

가변 인수 범위 (Vararg scope)

매개 변수 설명
position 가변 인수 배열 인수의 위치
nArgs 가변 인수 배열 인수의 총

출처




최종 수정 : 2024-04-23