Mockito を Kotlin で使うなら mockito-kotlin を使おう

この記事では、Mockito 自体の使い方などは書きませんのでご注意下さい。
Android向けの記述が多く含まれます。

## そのまま使うと起きる問題

Mockito をそのまま Kotlin で使うと以下のようなコードになると思います。

```kotlin
val sharedPreferences = mock(SharedPreferences::class.java)
val editor = mock(SharedPreferences.Editor::class.java, RETURNS_DEEP_STUBS)

`when`(sharedPreferences.edit()).thenReturn(editor)
`when`(editor.commit()).thenReturn(true)
`when`(editor.putString(anyString(), anyString())).thenReturn(editor)
```

上のコードは、Android の SharedPreferences をモック化するコードです。
`sharedPreferences.edit()` で更にモック化された Editor を返し、`commit()` と `putString()` を使えるようにしています。

モックオブジェクトの作成を行う、`mock()`メソッドはまあいいとして、モックオブジェクトの動作を決める`when()`メソッドの部分がバッククオートで囲まれており、非常に見にくいです。

これは、Kotlin では`when` という単語は予約語になってしまうため、バッククオートによるエスケープが必要になってしまうために起きる現象です。

もちろんこのままでも問題は無いのですが、せっかくなので今回はこのモックの作成コードの部分をより Kotlin らしくかけるライブラリ、 [**mockito-kotlin**](https://github.com/nhaarman/mockito-kotlin) を使ってみたいと思います。

## 環境

- Kotlin 1.2.40
- Mockito 2.18.3
- mockito-kotlin 1.5.0 https://github.com/nhaarman/mockito-kotlin

## 依存の追加

Gradle や Maven など、それぞれの方法でライブラリの参照を追加します。

```groovy
// testImplementation とかは環境に合わせる
testImplementation "com.nhaarman:mockito-kotlin:1.5.0"
```

## 使い方

### モックオブジェクトの作成

引数でクラスを渡すのではなく、ジェネリクスで指定するようになります。

```kotlin
val sharedPreferences = mock<SharedPreferences> {}
```

第2引数以降で渡していたオプションは、引き続きメソッドの引数に記述します。

```kotlin
val editor = mock<SharedPreferences.Editor>(defaultAnswer = RETURNS_DEEP_STUBS) { }
```

`withSettings()`の内容も、全て引数で渡すことができます。

```kotlin
// 使える引数は以下(1.5.0現在)
extraInterfaces: Array<KClass<out Any>>? = null
name: String? = null
spiedInstance: Any? = null
defaultAnswer: Answer<Any>? = null
serializable: Boolean = false
serializableMode: SerializableMode? = null
verboseLogging: Boolean = false
invocationListeners: Array<InvocationListener>? = null
stubOnly: Boolean = false
useConstructor: Boolean = false
outerInstance: Any? = null
stubbing: KStubbing<T>.(T) -> Unit
```

### モックオブジェクトの動作の指定

`when`は使わず、モック作成時の関数引数 `{ }` の内部に記述します。
`on { モックするメソッド() } ` で動作をモックするメソッドを指定し、その後に続けて、`doReturn`, `doAnswer`, `doThrow`と続きます。
下のコードは、記事の初めで紹介した Mockito をそのまま使用したコードと等価です。

```kotlin
val editor = mock<SharedPreferences.Editor>(defaultAnswer = RETURNS_DEEP_STUBS) {
    on { commit() } doReturn true
    on { putString(anyString(), anyString()) } doReturn it
}
val sharedPreferences = mock<SharedPreferences> {
    on { edit() } doReturn editor
}

// 以下、記事のはじめに出たコード
val sharedPreferences = mock(SharedPreferences::class.java)
val editor = mock(SharedPreferences.Editor::class.java, RETURNS_DEEP_STUBS)

`when`(sharedPreferences.edit()).thenReturn(editor)
`when`(editor.commit()).thenReturn(true)
`when`(editor.putString(anyString(), anyString())).thenReturn(editor)
```

#### doReturn

続けて書いた値がモック対象のメソッドの返り値となります。
返り値が`void`または`Unit`の場合は、`Unit`を返せば問題ないです。

```kotlin
val stringMock = mock<String> {
    on { toString() } doReturn "mocked"
}
stringMock.toString() // => "mocked"
```

#### doAnswer

レシーバとしてモックしたオブジェクトを受け取り、そのメソッドが返すことになっている型を返す関数を記述します。
`let`みたいなものです。

```kotlin
val stringMock = mock<String> {
    on { toString() } doAnswer { "mocked" + it.hashCode() }
}
stringMock.toString() // => "mocked[数字]"
```

#### doThrow

続けて書いた例外を投げます。

```kotlin
val stringMock = mock<String> {
    on { toString() } doThrow RuntimeException()
}
stringMock.toString() // => RuntimeException
```

## おわりに

モックするメソッドの引数の指定の部分では、Mockitoと同様に`any()`や`argThat()`も使えるので、基本は困ること無いと思います。
他の記述方法などについては、GithubのWikiや、テストのコードを見るとわかりやすいので、書き方わかんねぇと思ったら見るとよいでしょう。

Wiki: https://github.com/nhaarman/mockito-kotlin/wiki/Mocking-and-verifying
テストコード: https://github.com/nhaarman/mockito-kotlin/tree/2.x/tests/src/test/kotlin/test