Yappli Tech Blog

株式会社ヤプリの開発メンバーによるブログです。最新の技術情報からチーム・働き方に関するテーマまで、日々の熱い想いを持って発信していきます。

アサーションライブラリ「Truth」を使ってみた

こんにちは、株式会社ヤプリでAndroidエンジニアをしているdais-sasaです!

最近、弊社ではエンジニアが新技術に積極的に触れられるように、週に一度もくもく会を開催しています。
そこで、7月8日にバージョン1.0がリリースされたアサーションライブラリ「Truth」を試しに使ってみました。

本記事では、「Truth」を使うための設定や基本的な使い方について紹介します。

Androidエンジニアの皆さんの何かの参考になれば幸いです。

Truthとは

「Truth」とはGoogleから提供されているアサーションライブラリです。

truth.dev

「Truth」の場合、Boolean、Double、Float、Integer、Long、Stringといった基本的なものからThrowable、Iterable等にあわせた評価メソッドを提供しています。
また、評価メソッドを独自に作成する手段も提供しているので、それぞれのアプリに適した評価メソッドを用意しておくことが可能です。

Androidの場合JUnit4が入っている筈なので、アサーションライブラリがなくても、同値チェック、nullチェック、真偽値チェックが可能であり、これらのチェックを駆使すれば大体のテストの記述は可能ですが、「Truth」を使えば、より記述が容易になります。
特に、コレクションや例外に対する評価は、アサーションライブラリがあった方が簡単にテストを記述できるようになると思います。

なぜTruthを選んだか

Androidアプリのテストで用いるアサーションライブラリで最も利用されているのは、恐らく「AssertJ」になると思います。
実際、「Truth」で出来ることは、「AssertJ」でも可能なことがほとんどで、現状「AssertJ」の採用を退けてまで「Truth」を使うというのはケースとしては少ないでしょう。
そもそも、「Truth」は7月8日にバージョン1.0がリリースされたばかりなので、「Truth」でテストを記述しているAndroidアプリはほとんどないと思います。

それにも関わらず、「Truth」を使ってみたのはなぜか?

それは、AndroidX Test Library が 「Truth」向けの拡張を用意しているからです。

mvnrepository.com

また、「Truth」の公式ページにもGoogle内ではアサーションライブラリは「Truth」を使って開発していると記載があり、「Truth」は公式でサポートされたライブラリと言え、今後もAndroidに向けた開発が続けられそうだという「将来性」を感じたためでした。

実は、AssertJも以前はAndroid用のライブラリがあったのですが、サポートライブラリの進化への追従が難しいため廃止されたという経緯があります。

このことからも将来性という点では「Truth」に軍配が上がると判断し、試しに使ってみたという形になります。

Truthの使い方

設定

前提として、今回はAndroidXは入れてない状態で導入しています。

まずは、プロジェクトのbuild.gradleに以下を追加してください。 (大半のアプリではすでに記載されていると思うので、その場合はこのステップはとばしてください)

repositories {
    mavenCentral()
}

次に、テストを記述するモジュールのbuild.gradleに以下を追加してください。

dependencies {
    testImplementation "com.google.truth:truth:1.0"
}

基本的な、導入設定はこれで終了になります。
他にもいくつかの拡張があり、例えばJava8用の拡張は「com.google.truth.extensions:truth-java8-extension:1.0」、エラーメッセージの拡張は「org.ow2.asm:asm:someversion」を追加してください。
今回は基本的な機能の使用を目的としていたため、上記の拡張は導入せずに動作確認をしています。

基本実装

実際のテストケースの実装になります。

Hello World!という文字列がHelloで開始され、World!で終了になり、半角スペースを含むか?という簡単なテストケースを例にあげると以下のようになります。

Truth.assertThat("Hellow World!").apply {
    startsWith("Hellow")
    endsWith("World!")
    contains(" ")
}

上記の様に、基本的な使い方としては、assertThatの引数にテスト対象をセットして、それに対して、評価メソッドを叩くという形になります。
assertThatの引数にセットできる型は、公式ページに記載がありますので、そちらを参照してください。

truth.dev

今回は、「Truth」だけ導入してますが、androidx の Test Libraryを使った場合「Intent」「PendingIntent」「Notification」「Location」「Bundle」「Parcelable」「MotionEvent」の様なAndroid独自の型もassertThatにセットできる様になります。

また、上記にない型のオブジェクトを独自にテスト対象とすることが可能です。

独自評価の実装

「Truth」では事前に定義されていない型のオブジェクトに対しても、独自実装で評価メソッド等を定義することが可能です。

例えば、独自に定義した「User」という型のidが等しいかをテストする場合です。
まず、以下の様にSubjectクラスを継承したクラスを作ります。

class UserSubject(failureMetadata: FailureMetadata, val subject: User) : Subject(failureMetadata, subject) {

    fun isIdEqualTo(user: User) {
        check("getId()").that(subject.id).isEqualTo(user.id)
    }
}

そして、上記を利用してテストを記述すると以下の様に記載できます。

Truth.assertAbout { metadata: FailureMetadata, subject: User ->
    UserSubject(metadata, subject)
}.that(userA).apply {
    isIdEqualTo(userB)
}

assertAboutを使って、先ほど定義したSubjectを継承したクラスのコンストラクタを呼び出し、thatメソッドに対して評価対象のオブジェクトをセットします。
ここまでで基本実装の項目で記載したassertThatと同じ動作になります。

以降は、基本実装の時と同じ様に評価メソッドを叩いて評価を行います。
今回の場合、「isIdEqualTo」という評価メソッドをSubjectを継承したクラス内に記述することで独自評価メソッドの作成を行なっています。

なお、これだと読みづらい部分があるので、Truth用のUtilクラスみたいな物を作り以下の様に実装します。

object TruthUtil {

    /**
     * Userのsubjectを生成する
     */
    fun assertThat(user: User): UserSubject = Truth.assertAbout { metadata: FailureMetadata, subject: User ->
        UserSubject(metadata, subject)
    }.that(user)
}

上記のようなUtilを用意しておけば、テストは以下の様に記述できる様になります。

TruthUtil.assertThat(userA).isIdEqualTo(userB)

もうほとんど、基本の実装と同じ書き方になっていると思います。

最後に

いかがだったでしょうか。
今回紹介したのは「Truth」の基本的な使い方とちょっとした独自の評価メソッドの定義方法ですが、これが分かれば大体のテストは記述できる様になると思います。

「Truth」はまだまだリリースしたばかりで、「AssertJ」に比べると劣っている部分もあると思います。
しかし、「なぜTruthを選んだか」で記載した通り、今後Androidの開発を続けていくと「Truth」に触れる機会が増えていくことになりそうです。

これを機会に、「Truth」を使ってみて今後のアプリ開発に役立てていただければ幸いです。