Kotlin MockK の使い方 (公式ドキュメント翻訳)
はじめに
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 でも注入される。注入に使うコンストラクタは、引数が多いものから少ないものへ順に選択される。
デフォルトでは、@InjectMockKs は lateinit 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 回の検証
呼び出し回数は 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)
// 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)
これらの検証メソッドはすでに検証対象の呼び出しをすべてカバーするため、verifySequence と verifyAll を同時に使うことに大きな意味はない。
未検証の呼び出しが残っている場合は例外が発生する。
一部の呼び出しはこの確認から除外できる。詳細は次のセクションを参照する。
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) }
一致するすべての呼び出しが記録から除外される。これは 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) // 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 関数は 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) }
拡張関数
拡張関数には 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 を作ることもできる。
設定ファイル
グローバルにパラメータを調整するには、リソースファイルにいくつかの設定を指定する。
使い方:
- リソースファイル
io/mockk/settings.propertiesを作成する。 - 次のいずれかのオプションを入力する。
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 配列引数の総数。 |
出典
- 公式ドキュメント: https://mockk.io/