Truthのアサーション記述例

投稿日:  更新日:

Truthのアサーション記述例を紹介します。

Kotlinは「is」が予約語になっているので、Hamcrestで記述すると「`is`」になってしまいます。Java⇒Kotlinの自動変換を行ったら現れたのです。最初、変換ミスかと思いました。

動作に関係のない文字が入るのは嫌いです。

何か解決策はないかと、最近購入した書籍「みんなのKotlin」を見ていたらTruthがあるのを知りました。なかなか良いかも!

なので、今までHamcrestを使っていましたがTruthへ乗り換えます。

スポンサーリンク

Truthとは

TruthはAssertJやHamcrestと同じアサーションライブラリの一つです。

AndroidX Testの一部としてリリースされていて、現在(2020年9月)最新版はVer1.3.0になっています。積極的な開発が行われているようです。また、Truthの標準的なアサーション構文に加えて、Android向けの構文が存在しています。とても興味深いところです。今後、Androidと親和性が増していきそうな感じです。

Truthのさらなる情報はここを参照してください。

スポンサーリンク

環境設定

Truthを使うためにライブラリの依存リストへ次の一行を追加します。

dependencies {
    ...
    androidTestImplementation 'androidx.test.ext:truth:1.3.0'
    ...
}
\--- androidx.test.ext:truth:1.3.0
     +--- androidx.test:core:1.3.0 (*)
     +--- com.google.guava:guava:27.0.1-android
     +--- com.google.truth:truth:1.0
     \--- androidx.annotation:annotation:1.0.0

AndroidX(androidx.test.ext:truth)に組み困れているTruth本体(com.google.truth:truth)のバージョンはリリースノートを参照してください。

スポンサーリンク

アサーション記述例(標準的な構文)

※アサーション記述例は全てPassします
※Kotlinのコードのみ

Null

Kotlin
    @Test
    fun Nullテスト() {
        val s: String = "Yamada"
        val n: String? = null

        assertThat(n).isNull()          // nは Null である
        assertThat(s).isNotNull()       // sは Null でない
    }

Number

Kotlin
    @Test
    fun Numberテスト() {
        val n: Int = 5

        assertThat(n).isEqualTo(5)      // nは 5 と同じである
        assertThat(n).isNotEqualTo(0)   // nは 0 と同じでない

        assertThat(n).isGreaterThan(4)  // nは n>4 である
        assertThat(n).isLessThan(6)     // nは n<6 である
        assertThat(n).isAtLeast(5)      // nは n≧5 である
        assertThat(n).isAtMost(5)       // nは n≦5 である

        assertThat(n).isIn(1..10)       // nは 1~10 内である
        assertThat(n).isNotIn(6..10)    // nは 6~10 内でない

        assertThat(n).isAnyOf(4, 5, 6)  // n は 4,5,6 のいずれかである
    }

Boolean

Kotlin
    @Test
    fun Booleanテスト() {
        val t: Boolean = true
        val f: Boolean = false

        assertThat(t).isEqualTo(true)       // tは true と同じである
        assertThat(f).isNotEqualTo(true)    // fは true と同じでない

        assertThat(t).isTrue()              // tは true である
        assertThat(f).isFalse()             // fは false である
    }

String

Kotlin
    @Test
    fun Stringテスト() {
        val s: String = "abcdefg"
        val e: String = ""

        assertThat(s).isEqualTo("abcdefg")      // sは "abcdefg" と同じである
        assertThat(s).isNotEqualTo("hijklmn")   // sは "hijklmn" と同じでない

        assertThat(s).startsWith("abc")         // sは "abc" で始まる
        assertThat(s).endsWith("efg")           // sは "efg" で終わる
        assertThat(s).contains("cde")           // sは "cde" を含む
        assertThat(s).doesNotContain("c_e")     // sは "c_e" を含まない

        assertThat(s).matches("a.*g")            // sは 正規表現:"a.*g" に一致する
        assertThat(s).doesNotMatch("h.*n")       // sは 正規表現:"h.*n" に一致しない
        assertThat(s).containsMatch("c.e")       // sは 正規表現:"c.e" に一致する部分を含む
        assertThat(s).doesNotContainMatch("j.k") // sは 正規表現:"j.k" に一致する部分を含まない

        assertThat(s).isAnyOf("123", "abcdefg", "456") //  sは 指定要素 のいずれかである

        assertThat(e).isEmpty()                 // eは空である
        assertThat(s).isNotEmpty()              // sは空でない

        assertThat(s).hasLength(7)              // sは 7 の長さを持つ
    }

Array

Kotlin
    @Test
    fun Arrayテスト(){
        val c: Array<String> = arrayOf("abc", "def", "ghi")
        val e: Array<String> = arrayOf()

        assertThat(c).isEqualTo(arrayOf("abc", "def", "ghi"))    // cは 指定配列 と同じである
        assertThat(c).isNotEqualTo(arrayOf("abc", "jkl", "ghi")) // cは 指定配列 と同じでない

        assertThat(c).hasLength(3)  // cは 3 の長さを持つ
        assertThat(e).isEmpty()     // eは空である
        assertThat(c).isNotEmpty()  // cは空でない
    }

List

Kotlin
    // ・containsAllOf()/containsAllIn() はTruth 0.46で廃止されました。
    //  代わりにcontainsAtLeast()/containsAtLeastElementsIn()を使います。
    @Test
    fun Listテスト(){
        val l: List<String> = listOf("Tokyo", "Osaka", "Nagoya")
        val e: List<String> = listOf()

        // ※Listは順番を問うコレクションである
        assertThat(l).isEqualTo(listOf("Tokyo", "Osaka", "Nagoya"))    // lは 指定リスト (順番&数一致)と同じである
        assertThat(l).isNotEqualTo(listOf("Tokyo", "Osaka", "A"))      // lは 指定リスト (順番&数一致)と同じでない
        assertThat(l).isNotEqualTo(listOf("Nagoya", "Osaka", "Tokyo")) // lは 指定リスト (順番&数一致)と同じでない
        assertThat(l).isNotEqualTo(listOf("Tokyo", "Osaka"))           // lは 指定リスト (順番&数一致)と同じでない

        assertThat(l).contains("Osaka")     // lは 指定の要素 を含む
        assertThat(l).doesNotContain("A")   // lは 指定の要素 を含まない

        assertThat(l).containsExactly("Tokyo", "Nagoya", "Osaka") // lは 指定要素 の全て(順番不問、数一致)を含む
//        assertThat(l).containsAllOf("Nagoya", "Tokyo")            // lは 指定要素 の全て(順番不問、数不問)を含む
        assertThat(l).containsAtLeast("Nagoya", "Tokyo")          // lは 少なくとも指定要素(順番不問、数不問)を含む
        assertThat(l).containsAnyOf("A", "Nagoya", "B")           // Lは 指定要素 のいずれかを含む
        assertThat(l).containsNoneOf("A", "B")                    // lは 指定要素 の全てを含まない

//        assertThat(l).containsAllIn(listOf("Nagoya", "Tokyo"))    // Lは 指定リスト の要素の全て(順番不問、数不問)を含む
        assertThat(l).containsAtLeastElementsIn(listOf("Nagoya", "Tokyo"))// Lは 少なくとも指定リスト の要素(順番不問、数不問)を含む
        assertThat(l).containsAnyIn(listOf("A", "Nagoya", "B"))   // Lは 指定リスト の要素のいずれかを含む
        assertThat(l).containsNoneIn(listOf("A", "B"))            // lは 指定リスト の要素の全てを含まない

        assertThat(l).containsNoDuplicates()  // L は 重複した要素 を含まない

        assertThat(l).hasSize(3)    // Lは 3 のサイズを持つ
        assertThat(e).isEmpty()     // eは 空 である
        assertThat(l).isNotEmpty()  // lは 空 でない
    }

Map

Kotlin
    @Test
    fun Mapテスト(){
        val m: Map<String, Int> = mapOf("Tokyo" to 3, "Nagoya" to 52, "Osaka" to 6)
        val e: Map<String, Int> = mapOf()

        // ※Mapは順番を問わないコレクションである
        assertThat(m).isEqualTo(mapOf("Tokyo" to 3, "Nagoya" to 52, "Osaka" to 6)) // mは 指定マップ(順番不問&数一致)と同じである
        assertThat(m).isEqualTo(mapOf("Nagoya" to 52, "Osaka" to 6, "Tokyo" to 3)) // mは 指定マップ(順番不問&数一致)と同じである
        assertThat(m).isNotEqualTo(mapOf("Tokyo" to 3, "Nagoya" to 52, "A" to 0))  // mは 指定マップ(順番不問&数一致)と同じでない
        assertThat(m).isNotEqualTo(mapOf("Tokyo" to 3, "Nagoya" to 52))            // mは 指定マップ(順番不問&数一致)と同じでない

        assertThat(m).containsEntry("Osaka", 6)     // mは 指定エントリー を含む
        assertThat(m).doesNotContainEntry("A", 0)   // mは 指定エントリー を含まない
        assertThat(m).containsKey("Osaka")          // mは 指定キー を含む
        assertThat(m).doesNotContainKey("A")        // mは 指定キー を含まない

        assertThat(m).containsExactly("Nagoya", 52, "Osaka", 6, "Tokyo", 3) // mは 指定エントリーの全て(順番不問、数一致)を含む

        assertThat(m).containsExactlyEntriesIn(mapOf("Osaka" to 6, "Tokyo" to 3, "Nagoya" to 52)) // isEqualToと同じ

        assertThat(m).hasSize(3)    // mは 3 のサイズを持つ
        assertThat(e).isEmpty()     // eは空である
        assertThat(m).isNotEmpty()  // mは空でない
    }

Instance

Kotlin
    // ・isSameAs()/isNotSameAs() はTruth 0.45で廃止されました。
    //  isSameInstanceAs()/isNotSameInstanceAs()を使います。
    @Test
    fun Instanceテスト(){
        val s: SampleA = SampleA()
        val t: SampleA = SampleA()
        val u: SampleB = SampleB()
        val o: SampleA = s

//        assertThat(s).isSameAs(o)       // sは o と同じインスタンスである
        assertThat(s).isSameInstanceAs(o)    // sは o と同じインスタンスである
//        assertThat(s).isNotSameAs(t)    // sは t と同じインスタンスでない
        assertThat(s).isNotSameInstanceAs(t) // sは t と同じインスタンスでない
        assertThat(s).isInstanceOf(SampleA::class.java)    // sは SampleAクラス のインスタンスである
        assertThat(s).isNotInstanceOf(SampleB::class.java) // sは SampleBクラス のインスタンスでない
    }

Exception

Kotlin
    @Test
    fun Exception(){
        val e: Exception = IllegalArgumentException("Must be AAA")
        val x: Exception = Exception("Argument?", e)

        assertThat(e).isInstanceOf(IllegalArgumentException::class.java)
        // ↑ eは IllegalArgumentExceptionクラス のインスタンスである
        assertThat(e).hasMessageThat().isEqualTo("Must be AAA")
        // ↑ eが持つメッセージは "Must be AAA" と同じである

        assertThat(x).isInstanceOf(Exception::class.java)     
        // ↑ xは Exceptionクラス のインスタンスである
        assertThat(x).hasMessageThat().isEqualTo("Argument?")
        // ↑ xが持つメッセージは "Argument" と同じである
        assertThat(x).hasCauseThat().isInstanceOf(IllegalArgumentException::class.java)
        // ↑ xが持つCauseは IllegalArgumentExceptionクラス のインスタンスである
        assertThat(x).hasCauseThat().hasMessageThat().isEqualTo("Must be AAA")
        // ↑ xが持つCauseのメッセージは "Must be AAA" と同じである
    }
スポンサーリンク

アサーション記述例(Android向け構文)

表にあげた構文がサポートされています。

さらなる詳細は各Subjectのドキュメントを参照してください。


SubjectPackage記述例
BundleSubjectandroidx.test.ext.truth.os
IntentSubjectandroidx.test.ext.truth.content
NotificationActionSubjectandroidx.test.ext.truth.app
NotificationSubject
PendingIntentSubject
MotionEventSubjectandroidx.test.ext.truth.view
PointerCoordsSubject
PointerPropertiesSubject

※アサーション記述例は全てPassします
※Kotlinのコードのみ

Bundle

Kotlin
    @Test
    fun Bundleテスト(){
        val b: Bundle = Bundle()
        b.putInt("ikey", 1)
        b.putLong("lkey", 2L)
        b.putBoolean("bkey", true)
        b.putString("skey", "abc")

        val bSub_b: BundleSubject = BundleSubject.assertThat(b)
        bSub_b.containsKey("ikey")       // bは Key="ikey" を含む
        bSub_b.doesNotContainKey("xkey") // bは Key="xkey" を含まない

        bSub_b.integer("ikey").isEqualTo(1)     // bのintegerは 1 と同じである
        bSub_b.longInt("lkey").isEqualTo(2L)    // bのlongは 2 と同じである
        bSub_b.bool("bkey").isTrue()            // bのboolは true である
        bSub_b.string("skey").isEqualTo("abc")  // bのstringは "abc" と同じである
    }

Intent

Kotlin
    @Test
    fun Intentテスト(){
        val i: Intent = Intent()
        i.putExtra("ikey", 1)
        i.putExtra("lkey", 2L)
        i.putExtra("bkey", true)
        i.putExtra("skey", "abc")

        val uri = Uri.parse("file:///sdcard/SampleText.txt")
        val j: Intent = Intent(Intent.ACTION_VIEW)
        j.setDataAndType(uri, "text/plain")
        val m: Intent = Intent(Intent.ACTION_VIEW)
        m.setDataAndType(uri, "text/plain")

        val context: Context = InstrumentationRegistry.getInstrumentation().targetContext
        val k: Intent = Intent(context, MainActivity::class.java)

        val bSub_i: BundleSubject = IntentSubject.assertThat(i).extras()
        val iSub_i: IntentSubject = IntentSubject.assertThat(i)
        val iSub_j: IntentSubject = IntentSubject.assertThat(j)
        val iSub_k: IntentSubject = IntentSubject.assertThat(k)

        bSub_i.integer("ikey").isEqualTo(1)    // iのintegerは 1 と同じである
        bSub_i.longInt("lkey").isEqualTo(2L)   // iのlongは 2 と同じである
        bSub_i.bool("bkey").isEqualTo(true)    // iのboolは true と同じである
        bSub_i.string("skey").isEqualTo("abc") // iのstringは "abc" と同じである

        iSub_i.hasNoAction()                    // iは Action を持たない
        iSub_j.hasAction(Intent.ACTION_VIEW)    // jは Action=ACTION_VIEW を持つ
        iSub_j.hasData(Uri.parse("file:///sdcard/SampleText.txt")) // jは Uri="file:..." を持つ
        iSub_j.hasType("text/plain")            // jは Type="text/plain" を持つ
        iSub_j.filtersEquallyTo(m)              // jは m と同じフィルターである

        iSub_k.hasComponentClass("パッケージ名.MainActivity") // kは Class=MainActivity を持つ
        iSub_k.hasComponentClass(MainActivity::class.java)    // kは Class=MainActivity を持つ
        iSub_k.hasComponentPackage("パッケージ名")            // kは Package=パッケージ名 を持つ
    }
スポンサーリンク
スポンサーリンク