KotlinのJUnitTestにおけるアサーションライブラリはKluentがとても良い感じ

## JUnitのアサーションを快適に書きたい

KotlinでUnitTestを書いていて、今までさして調べずメジャーだからと言う理由で[Hamcrest](http://hamcrest.org/)を使ってたんですが、もともとJavaのライブラリなのでKotlinだと微妙に使いにくい部分がありました。

例えば型判定のアサーションを記述したいときは↓のように書きますが

```kotlin
val value = 10
assertThat(value, `is`(instanceOf(Int::class.java)))
```

Kotlinでは`is`が予約語に指定されているため``` ` ```で括る必要もあるのと、`is`と`instanceOf`がネストしているのも微妙に書きにくい&読みにくく、クラス指定も`::class.java`まで記述する必要があって、当たり前ですが`KClass`で記述できないのでJavaの世界観に引きづられている印象を受けます。

また細かいところだと、`is`メソッド一つとっても[Hamcrest](http://hamcrest.org/)内だけでも3つ`imoport`候補が出てきて、どれを`imoport`するんだっけ？と一瞬手が止まるのも書きにくいなぁと思っていた部分でした（ここはKotlin関係ない部分ですが）
<img width="499" alt="スクリーンショット 2020-08-08 21.47.29.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129872/5f26b17a-4627-6a57-60e5-88ecd022db03.png">

この辺はイマイチだなーと思いつつプロダクションに入らないコードだし動けばまあいいかと思っていたんですが、Kotlinに特化したアサーションライブラリを試しに使ってみたら思いの外快適に記述できて感動したので紹介します。

## Kluent

<img width="506" alt="スクリーンショット 2020-08-08 23.59.41.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129872/70e79d28-a1c5-8257-ced2-c2b55dfa7fa6.png">
**Docs: https://markusamshove.github.io/Kluent/**
**Github: https://github.com/MarkusAmshove/Kluent**

[Kluent](https://markusamshove.github.io/Kluent/)はKotlinに特化したJunitアサーションライブラリです。
`Fluent Assertion-Library for Kotlin`とあるように流れるように記述できるのが特徴です。

[Hamcrest](http://hamcrest.org/)が**staticメソッド**を軸にアサーションを実装しているのに対し、[Kluent](https://markusamshove.github.io/Kluent/)はKotlinの**拡張関数**や**infix記法（中置記法）**を軸にアサーションが実装されています。

### アサーション比較

公式サイトへのリンク先に使い方がわかりやすく乗っているのでぱっと見で理解できるとは思いますが、1例として上記で扱った型判定のアサーションで[Hamcrest](http://hamcrest.org/)と[Kluent](https://markusamshove.github.io/Kluent/)を比較してみます。

```kotlin:Hamcrest
val value = 10
assertThat(value, `is`(instanceOf(Int::class.java)))
```

```kotlin:Kluent
val value = 10
value shouldBeInstanceOf Int::class
```

どうでしょうか、カッコもなくなりだいぶ読みやすく書きやすくなったと思います。
[Hamcrest](http://hamcrest.org/)はstaticメソッドである関係上Utilクラスのように手前に`assertThat`メソッドを書かなくてはいけませんが、[Kluent](https://markusamshove.github.io/Kluent/)はinfix記法のおかげで「valueはint型でなければならない」という英文を違和感なく構築することができています。

もちろんinfix記法でも補完が効きます。とりあえず`should...`と打てば必要なものが見つかると思います。
<img width="298" alt="スクリーンショット 2020-08-08 22.11.52.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129872/fda6329c-2486-8364-77e7-89d3d21b1c19.png">

また、infix以外にも拡張関数で定義されたアサーションもあり、nullチェックなどがそれに当たります。

```kotlin:Hamcrest
val value = 10
assertThat(value, `is`(notNullValue()))
```

```kotlin:Kluent
val value: Int? = 10
value.shouldNotBeNull()
```

そらで書く場合どちらのほうが記述しやすいかは一目瞭然ですね！
私自身[Kluent](https://markusamshove.github.io/Kluent/)の基本的な機能しかまだ使っていませんが、サイトのドキュメントを見る限り一般的にアサーションで最低限必要とされるものは揃っていると思います。

### モック機能

[Kluent](https://markusamshove.github.io/Kluent/)にはMocking機能があり、サイト内の解説によると[Mockito-Kotlin](https://github.com/nhaarman/mockito-kotlin)のラッパーとしての役割も担っているそうです。

```kotlin:Kluent
val mock = mock(Database::class)
mock.getPerson(1)
```

私は[MockK](https://github.com/mockk/mockk)に慣れきっていたので使いませんでしたが[Mockito-Kotlin](https://github.com/nhaarman/mockito-kotlin)を使っている方であれば嬉しいポイントかもしれません。

### Androidで使う場合

これは正直ちゃんとはわからなかった部分だったのですが、Githubの[ドキュメント](https://github.com/MarkusAmshove/Kluent#gradle)によるとAndroidで使う場合にはartifactが異なり、以下を指定する必要があるそうです。

```groovy:build.gradle
// for JVM:
testImplementation 'org.amshove.kluent:kluent:{version}'
// for Android:
testImplementation 'org.amshove.kluent:kluent-android:{version}'
```

この違いについてはドキュメントには記載がなかったのですが、2020/08/08現在のリポジトリ内をざっくり検索したところライブラリの機能や含まれているソースコード自体には違いはなく、JVMによる実行環境とAndroid上の実行環境の差異を吸収するためにartifactが別れているようでした。

これが正しければですが、Androidデバイス上で実行される[Instrumented Test](https://developer.android.com/training/testing/unit-testing/instrumented-unit-tests)は`org.amshove.kluent:kluent-android`を使う必要がありますが、Androidのプロジェクトであってもデバイスを伴わずPC上のJVM環境で実行される[UnitTest](https://developer.android.com/training/testing/unit-testing/local-unit-tests)や[Robolectric](http://robolectric.org/)を使ったテストは`org.amshove.kluent:kluent`で十分と思われます。

## まとめ

[Kluent](https://markusamshove.github.io/Kluent/)はいいぞ！