はじめに
MockKとは Kotlin用のモックライブラリ です。
この記事では公式ドキュメントを日本語に訳し、自分用に使い方をまとめたものになります。これから辞書代わりに使っていこうと考えています。
私自身まだ実践で使ったことない機能もありますので、ニュアンス違うよなどの指摘やアドバイスを頂けると幸いです。
インストレーション(Installation)
始めるために必要なことは、MockK
ライブラリに依存関係を追加することです。
Gradle / Mavenの依存関係(Gradle/maven dependency)
アプローチ | 命令 |
---|---|
Gradle | testImplementation "io.mockk:mockk:{version}" |
Gradle(Kotlin DSL) | testImplementation("io.mockk:mockk:{version}") |
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の例(DSL examples)
最も単純な例です。デフォルトではモックは厳密なので、何らかの動作を提供する必要があります。
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
が適用されている場合でも、プロパティが注入されます。インジェクションのコンストラクターは、引数の最大数から最小数まで選択されます。
デフォルトでは、@InjectMockKs
は、lateinit 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
を使用する際は、戻り値がジェネリックではうまく機能しません。通常、この場合、クラスキャスト例外がスローされます。戻り値がジェネリックの場合、スタブを手動で指定する必要があります。
回避策:
val func = mockk<() -> Car>(relaxed = true) // この場合、invoke関数は戻り値にジェネリックを持ちます
// この行は回避策です。この行がないと`relaxed mock`は次の行でクラスキャスト例外をスローします
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
のクラスごとに1つのインスタンスがあります。コールの記録は、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
に使用することはあまり意味がありません。
いくつかの呼び出しが検証なしで残っている場合、例外をスローします。
一部の呼び出しはこのような確認からスキップされる場合があります。詳細については次のセクションを確認してください。
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)
拡張関数には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)
// 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 = 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") }
プロパティバッキングフィールド(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)
パラメータをグローバルに調整するには、リソースファイルでいくつかの設定を指定します。
使い方:
- リソースに
io/mockk/settings.properties
ファイルを作成します。 - 次のオプションのいずれかを入力します。
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) |
論理積で2つのマッチャーを結合します |
or(left, right) |
論理和で2つのマッチャーを結合します |
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)
アンサーの後に、1つ以上の追加のアンサーが続く場合があります。
アンサー | 説明 |
---|---|
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 |
一致した呼び出しが1つの指定された値を返すことを指定します |
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 |
可変引数配列の引数の総数 |
おわりに
公式ドキュメントでは使用例が掲載されていない機能も多数あるので、GitHubのサンプルコードからも引っ張ってこようと思ってます。
終盤、心が折れそうになりました。
スラスラとUnit Test書けるようになりたい。(大抵なにかしらで躓いてます...)