Kotlin MockK の使い方 (公式ドキュメント翻訳)

MockK はテストコードを書くための Kotlin 向けモックライブラリである。この文書は公式ドキュメントをもとにした日本語訳である。

はじめに

MockK はテストコードを書くための Kotlin 向けモックライブラリである。この文書は 公式ドキュメント をもとにしている。

インストール

まず 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)

アノテーション

アノテーションを使うと、モックオブジェクトの作成を簡潔にできる。

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) // turns on relaxUnitFun for all mocks

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

注入はまずプロパティ名で照合し、その後クラスまたはスーパークラスで照合する。動作をカスタマイズするには lookupType パラメータを確認する。

プロパティが private でも注入される。注入に使うコンストラクタは、引数が多いものから少ないものへ順に選択される。

デフォルトでは、@InjectMockKslateinit var または未代入の var プロパティだけに注入する。変更するには overrideValues = true を使う。これは、すでに何らかの形で初期化されていても値を代入する。val に注入するには injectImmutable = true を使う。短い書き方として @OverrideMockKs も使える。これはデフォルトでは @InjectMockKs と同じように動作するが、両方のフラグを有効にする。

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

Spy はモックと実オブジェクトを組み合わせられる。

val car = spyk(Car()) // or spyk<Car>() to call the default constructor

car.drive(Direction.NORTH) // returns the real function returned by Car

verify { car.drive(Direction.NORTH) }

confirmVerified(car)

注意: Spy オブジェクトは渡されたオブジェクトのコピーである。

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 ではジェネリックな戻り値はうまく動作しない。この場合、通常はクラスキャスト例外が発生する。戻り値がジェネリックなら、スタブを手動で指定する。

回避策:

val func = mockk<() -> Car>(relaxed = true) // in this case invoke has a generic return value

// this line is the workaround. Without it, the relaxed mock throws a class cast exception on the next line
every { func() } returns Car() // or return mockk(), for example

func()

Unit を返す関数の Relaxed mock

Unit を返す関数だけを relaxed にしたい場合は、mockk 関数、@MockK アノテーション、または MockKAnnotations.init 関数の引数に relaxUnitFun = true を指定する。

mockk 関数:

mockk<MockCls>(relaxUnitFun = true)

@MockK アノテーション:

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

MockKAnnotations.init 関数:

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

オブジェクトモック

オブジェクトは次のようにモックへ変換できる。

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

mockkObject(MockObj) // applies to the object mock

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>()

クラスモック

クラスのモックが必要な場合がある。その場合は 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) }

列挙型のモック

Enum は 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)

コンストラクタモック

特に自分が管理していないコードでは、新しく作成されるオブジェクトをモックしたい場合がある。そのために次の設定が用意されている。

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)) // note that a new object is created

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

基本的な考え方は、モック対象クラスのコンストラクタが実行された直後に、そのオブジェクトが constructed mock になるというものだ。このようなオブジェクトのモック動作は、anyConstructed<MockCls>() で表される特別な prototype mock に接続される。この prototype mock はクラスごとに 1 つ存在する。呼び出しの記録も prototype mock 上で行われる。関数が指定されていない場合は元の関数が実行される。

引数の部分マッチング

通常の引数と matcher を混在させることができる。

val car = mockk<Car>()

every { 
  car.recordTelemetry(
    speed = more(50),
    direction = Direction.NORTH, // "eq()" is used here
    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)

チェーン呼び出し

呼び出しチェーンをスタブできる。

val car = mockk<Car>()

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

car.door(DoorType.FRONT_LEFT) // returns Door chained mock
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

階層モック

バージョン 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"
            }
        }
    )
}

キャプチャ

引数は 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)

atLeast、atMost、exactly 回の検証

呼び出し回数は atLeastatMostexactly パラメータで確認できる。

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

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

// all pass
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) } // means it was not called

confirmVerified(car)

検証順序

  • 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)

検証の確認

すべての呼び出しが verify... 構文で検証されたかを二重に確認するには、confirmVerified を使う。

confirmVerified(mock1, mock2)

これらの検証メソッドはすでに検証対象の呼び出しをすべてカバーするため、verifySequenceverifyAll を同時に使うことに大きな意味はない。

未検証の呼び出しが残っている場合は例外が発生する。

一部の呼び出しはこの確認から除外できる。詳細は次のセクションを参照する。

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) // confirms that all calls were verified

記録の除外

重要度の低い呼び出しを記録から除外するには、excludeRecords を使う。

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

一致するすべての呼び出しが記録から除外される。これは verifyAllverifySequenceconfirmVerified のような包括的な検証を使うときに便利である。

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) // only car.drive(Direction.NORTH) needs confirmation because car.drive(Direction.SOUTH) was excluded

検証タイムアウト

並行処理を検証するには、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 を返す

関数が 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)
}

コルーチン

コルーチンをモックするには、サポートライブラリへの依存関係を追加する。

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>

その後、suspend 関数は coEverycoVerifycoMatchcoAssertcoRuncoAnswerscoInvoke でモックできる。

val car = mockk<Car>()

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

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

coVerify { car.drive(Direction.NORTH) }

拡張関数

拡張関数には 3 つのケースがある。

  • 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)

// declared in File.kt in the "pkg" package
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 以降では、より高度な vararg 処理を利用できる。

    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 関数のモック / 動的呼び出し

private 関数をモックする必要がある場合は、動的呼び出しを通じて行える。

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"]()
}

private 呼び出しを検証するには、recordPrivateCalls = true を指定して spyk を作成する。

同じ動的呼び出し構文は、プロパティの取得と設定にも使える。

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") }

プロパティのバッキングフィールド

fieldValue でバッキングフィールドのプロパティにアクセスでき、設定される値には value を使う。

注意: 次の例では fieldValue の型を指定するために propertyType を使っている。これは getter の型は自動でキャプチャできるためである。nullable 型を指定するには nullablePropertyType を使う。

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
}

複数インターフェース

インターフェースを通じて追加の振る舞いを加え、それをスタブできる。

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()

Nothing のモック

ここに特別なことはない。Nothing を返す関数がある場合:

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

たとえば、振る舞いとして例外を投げるようにできる。

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

Matcher の拡張

非常に簡単な方法は、MockKMatcherScope または MockKVerificationScope に関数を追加し、match 関数を使って新しい matcher を作ることである。

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

Matcher インターフェースを実装して、より高度な matcher を作ることもできる。

設定ファイル

グローバルにパラメータを調整するには、リソースファイルにいくつかの設定を指定する。

使い方:

  1. リソースファイル io/mockk/settings.properties を作成する。
  2. 次のいずれかのオプションを入力する。
relaxed=true|false
relaxUnitFun=true|false
recordPrivateCalls=true|false

DSL テーブル

次の表は DSL を理解するための参考になる。

トップレベル関数

関数 説明
mockk<T>(...) 通常のモックを作成する。
spyk<T>() デフォルトコンストラクタを使って spy を作成する。
spyk(obj) obj をコピーして spy を作成する。
slot キャプチャスロットを作成する。
every スタブブロックを開始する。
coEvery コルーチン用スタブブロックを開始する。
verify 検証ブロックを開始する。
coVerify コルーチン用検証ブロックを開始する。
verifyAll すべての呼び出しを含む検証ブロックを開始する。
coVerifyAll すべてのコルーチン呼び出しを含む検証ブロックを開始する。
verifyOrder 順序を確認する検証ブロックを開始する。
coVerifyOrder コルーチン呼び出しの順序を確認する検証ブロックを開始する。
verifySequence すべての呼び出しが指定された順序で発生したかを確認する検証ブロックを開始する。
coVerifySequence すべてのコルーチン呼び出しが指定された順序で発生したかを確認する検証ブロックを開始する。
excludeRecords 一部の呼び出し記録を除外する。
confirmVerified 記録されたすべての呼び出しが検証済みであることを確認する。
clearMocks 指定したモックをクリアする。
registerInstanceFactory 特定のオブジェクトのインスタンス化方法を再定義できるようにする。
mockkClass クラスをパラメータとして渡して通常のモックを作成する。
mockkObject 任意のオブジェクトをモックする。すでに変換済みなら解除する。
unmockkObject オブジェクトモックを通常のオブジェクトへ戻す。
mockkStatic クラス内の static メンバーをモックする。すでに変換済みなら解除する。
unmockkStatic static モックを通常のクラスへ戻す。
clearStaticMockk static モックをクリアする。
mockkConstructor クラスのコンストラクタをモックする。すでに変換済みなら解除する。
unmockkConstructor コンストラクタモックを通常のクラスへ戻す。
clearConstructorMockk コンストラクタモックをクリアする。
unmockkAll オブジェクトモック、static モック、コンストラクタモックを解除する。
clearAllMocks 通常のモック、オブジェクトモック、static モック、コンストラクタモックをクリアする。

Matchers

デフォルトでは、単純な引数は eq() を使って照合される。

Matcher 説明
any() 任意の引数に一致する。
allAny() 単純な引数に eq() ではなく any() を使う特別な matcher。
isNull() 値が null かを確認する。
isNull(inverse=true) 値が null でないかを確認する。
ofType(type) 値がその型に属するかを確認する。
match { it.startsWith("string") } 渡された述語で一致させる。
coMatch { it.startsWith("string") } 渡されたコルーチン述語で一致させる。
matchNullable { it?.startsWith("string") } nullable 値を渡された述語で一致させる。
coMatchNullable { it?.startsWith("string") } nullable 値を渡されたコルーチン述語で一致させる。
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) 2 つの matcher を論理 AND で結合する。
or(left, right) 2 つの matcher を論理 OR で結合する。
not(matcher) matcher を否定する。
capture(slot) CapturingSlot の値をキャプチャする。
capture(mutableList) 値をリストにキャプチャする。
captureNullable(mutableList) null 値を含めて値をリストにキャプチャする。
captureLambda() ラムダをキャプチャする。
captureCoroutine() コルーチンをキャプチャする。
invoke(...) 一致した引数を呼び出す。
coInvoke(...) 一致したコルーチン引数を呼び出す。
hint(cls) 型が消去された場合に、次の戻り値型を示す。
anyVararg() vararg のすべての要素に一致する。
varargAny(matcher) 1 つの要素が matcher に一致すれば一致する。
varargAll(matcher) すべての要素が matcher に一致すれば一致する。
any...Vararg() プリミティブ型ごとに、vararg のすべての要素に一致する。
varargAny...(matcher) プリミティブ型ごとに、1 つの要素が matcher に一致すれば一致する。
varargAll...(matcher) プリミティブ型ごとに、すべての要素が matcher に一致すれば一致する。

一部の特別な matcher は検証モードでのみ使用できる。

Matcher 説明
withArg { code } 任意の値に一致し、コードを実行できる。
withNullableArg { code } nullable 値に一致し、コードを実行できる。
coWithArg { code } 任意の値に一致し、コルーチンコードを実行できる。
coWithNullableArg { code } nullable 値に一致し、コルーチンコードを実行できる。

Validators

Validator 説明
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

1 つ以上の追加 answer を answer の後に続けることができる。

Helper 説明
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 バッキングフィールドアクセサの型を nullable として指定する。

追加 answer

各結果の呼び出しは次の answer を返し、最後の値は保持される。これは returnsMany の意味に似ている。

追加 helper 説明
andThen value 一致した呼び出しが 1 つの指定値を返すことを指定する。
andThenMany list 一致した呼び出しがリストの値を順に返すことを指定する。
andThenThrows ex 一致した呼び出しが例外を投げることを指定する。
andThen { code } 一致した呼び出しが answer scope のコードブロックで応答することを指定する。
coAndThen { code } 一致した呼び出しが answer scope のコルーチンコードブロックで応答することを指定する。
andThenAnswer answerObj 一致した呼び出しが Answer オブジェクトで応答することを指定する。
andThen { nothing } 一致した呼び出しが null で応答することを指定する。

Answer scope

パラメータ 説明
call invocation と matcher で構成される呼び出しオブジェクト。
invocation 実際に呼び出された関数の情報を含む。
matcher 呼び出しの組み合わせに使われた matcher の情報を含む。
self 呼び出されたオブジェクトを参照する。
method 呼び出された関数を参照する。
args 呼び出し引数を参照する。
nArgs 呼び出し引数の数。
arg(n) n 番目の引数。
firstArg() 最初の引数。
secondArg() 2 番目の引数。
thirdArg() 3 番目の引数。
lastArg() 最後の引数。
captured() リストの最後の要素。リストにキャプチャするときに便利。
lambda<...>().invoke() キャプチャしたラムダを呼び出す。
coroutine<...>().coInvoke() キャプチャしたコルーチンを呼び出す。
nothing answer が何も返さない場合の null 値。
fieldValue プロパティのバッキングフィールドにアクセスする。
fieldValueAny プロパティのバッキングフィールドに Any? としてアクセスする。
value プロパティのバッキングフィールドと同じ型にキャストされた値。
valueAny 設定される値を Any? として表す。

Vararg scope

パラメータ 説明
position vararg 配列引数内の位置。
nArgs vararg 配列引数の総数。

出典