$30 off During Our Annual Pro Sale. View Details »

TruthとAssertJを比較してみた / Try to compared Truth and AsserJ

Dais-33
August 27, 2019

TruthとAssertJを比較してみた / Try to compared Truth and AsserJ

今年の7月に正式リリースされたGoogle製のアサーションライブラリであるTruthですが、調べてみると今後のAndroidではTruthを正式に使っていく流れになりそうでした(あくまで個人の予想ですが)。
なので、既存のアサーションライブラリと比較して、置き換えをしても問題ないかを検証しました。

Dais-33

August 27, 2019
Tweet

More Decks by Dais-33

Other Decks in Technology

Transcript

  1. 株式会社 ヤプリ
    XXXX
    株式会社 ヤプリ
    TruthとAssertJを⽐較してみた / Dais-33

    View Slide

  2. 株式会社 ヤプリ
    株式会社 ヤプリ
    • Name
    Ø 佐々⽊ ⼤輔
    • Twitter
    Ø @DaisSasa
    • Company
    Ø 株式会社ヤプリ
    • Job
    Ø Androidエンジニア
    ⾃⼰紹介
    Copyright © 2019 Yappli, Inc. All rights reserved.
    1

    View Slide

  3. 株式会社 ヤプリ
    株式会社 ヤプリ
    • サービス名
    Ø yappli
    • サービス内容
    Ø ⾮エンジニアがアプリ開発・運⽤できるようになるプラットフォーム
    Ø ⼀部機能を除きほぼネイティブで提供
    • エンジニアの役割
    Ø yappliで製作するアプリで使われる機能の原型の実装、改修を⾏います
    Androidに限らずアプリエンジニア募集中です
    興味がある⽅は、良ければ懇親会にてお声掛け下さい
    https://yapp.li/
    サービス紹介
    Copyright © 2019 Yappli, Inc. All rights reserved.
    2

    View Slide

  4. 株式会社 ヤプリ
    株式会社 ヤプリ
    Truthを試してみた背景
    Copyright © 2019 Yappli, Inc. All rights reserved.
    3
    • TruthはGoogleが提供しているアサーションライブラリ
    Ø 2019年7⽉8⽇にバージョン1.0が正式にリリースされたばかり
    • Google社内ではこのTruthを使って開発を⾏っている
    Ø Truthの公式ページにて記載されている
    • AndroidX Test LibraryにてTruth向けの拡張が⽤意されてある
    今後TruthがAndroidの正式なアサーションライブラリになるかも︖
    また、Android向けの開発も継続的に⾏われると予想
    (あくまで個⼈の予想です)

    View Slide

  5. 株式会社 ヤプリ
    株式会社 ヤプリ
    Truthを試してみた背景
    Copyright © 2019 Yappli, Inc. All rights reserved.
    4
    とはいえ、まだまだ正式リリースされたばかり、
    既存のライブラリから置き換えても⼤丈夫か︖

    という訳で、アサーションライブラリでよく使われている
    AssertJと使える機能の⽐較を⾏いました

    View Slide

  6. 株式会社 ヤプリ
    株式会社 ヤプリ
    ⽂字列のアサーション
    Copyright © 2019 Yappli, Inc. All rights reserved.
    5
    AssertJ
    Assertions.assertThat("TOKYO")
    .`as`("TEXT CHECK TOKYO")
    .isEqualTo("TOKYO")
    .isEqualToIgnoringCase("tokyo")
    .isNotEqualTo("KYOTO")
    .isNotBlank()
    .startsWith("TO")
    .endsWith("YO")
    .contains("OKY")
    .matches("[A-Z]{5}")
    .isInstanceOf(String::class.java)

    View Slide

  7. 株式会社 ヤプリ
    株式会社 ヤプリ
    ⽂字列のアサーション
    Copyright © 2019 Yappli, Inc. All rights reserved.
    6
    Truth
    Truth.assertWithMessage("TEXT CHECK TOKYO")
    .that("TOKYO").apply {
    isEqualTo("TOKYO")
    // isEqualToIgnoringCase("tokyo")
    isNotEqualTo("KYOTO")
    isNotEmpty()
    startsWith("TO")
    endsWith("YO")
    contains("OKY")
    matches("[A-Z]{5}")
    isInstanceOf(String::class.java)
    }

    View Slide

  8. 株式会社 ヤプリ
    株式会社 ヤプリ
    数値のアサーション
    Copyright © 2019 Yappli, Inc. All rights reserved.
    7
    AssertJ
    Assertions.assertThat(3.14159)
    .isNotZero()
    .isNotNegative()
    .isGreaterThan(3.0)
    .isLessThanOrEqualTo(4.0)
    .isBetween(3.0, 3.2)
    .isCloseTo(Math.PI, within(0.001))

    View Slide

  9. 株式会社 ヤプリ
    株式会社 ヤプリ
    数値のアサーション
    Copyright © 2019 Yappli, Inc. All rights reserved.
    8
    Truth
    Truth.assertThat(3.14159).apply {
    isNonZero()
    isAtLeast(0.0)
    isGreaterThan(3.0)
    isAtMost(4.0)
    // isBetween(3.0, 3.2)
    // isCloseTo(Math.PI, within(0.001))
    }

    View Slide

  10. 株式会社 ヤプリ
    株式会社 ヤプリ
    コレクションのアサーション
    Copyright © 2019 Yappli, Inc. All rights reserved.
    9
    AssertJ
    val target = listOf("Giants", "Dodgers", "Athletics")
    Assertions.assertThat(target)
    .hasSize(3)
    .contains("Dodgers")
    .containsOnly("Athletics", "Dodgers", "Giants")
    .containsExactly("Giants", "Dodgers", "Athletics")
    .doesNotContain("Padres")

    View Slide

  11. 株式会社 ヤプリ
    株式会社 ヤプリ
    コレクションのアサーション
    Copyright © 2019 Yappli, Inc. All rights reserved.
    10
    Truth
    val target = listOf("Giants", "Dodgers", "Athletics")
    Truth.assertThat(target).apply {
    hasSize(3)
    contains("Dodgers")
    containsAtLeast("Athletics", "Dodgers", "Giants")
    containsExactly("Giants", "Dodgers",
    "Athletics").inOrder()
    doesNotContain("Padres")
    }

    View Slide

  12. 株式会社 ヤプリ
    株式会社 ヤプリ
    フィルタリング
    Copyright © 2019 Yappli, Inc. All rights reserved.
    11
    AssertJ
    val target = listOf(
    BallTeam("Giants", "San Francisco", "AT&T Park"),
    BallTeam("Dodgers", "Los Angels", "Dodger Stadium"),
    BallTeam("Angels", "Los Angels", "Angel Stadium"),
    BallTeam("Athletics", "Oakland", "Oakland Coliseum"),
    BallTeam("Padres", "San Diego", "Petco Park")
    )
    Assertions.assertThat(target)
    .filteredOn { team -> team.city.startsWith("San") }
    .filteredOn { team -> team.city.endsWith("Francisco") }
    .extracting("name", String::class.java)
    .containsExactly("Giants")
    Assertions.assertThat(target)
    .filteredOn { team -> team.city == "Los Angels" }
    .extracting("name", "stadium")
    .containsExactly(
    tuple("Dodgers", "Dodger Stadium"),
    tuple("Angels", "Angel Stadium")
    )

    View Slide

  13. 株式会社 ヤプリ
    株式会社 ヤプリ
    フィルタリング
    Copyright © 2019 Yappli, Inc. All rights reserved.
    12
    Truth
    val target = listOf(
    BallTeam("Giants", "San Francisco", "AT&T Park"),
    BallTeam("Dodgers", "Los Angels", "Dodger Stadium"),
    BallTeam("Angels", "Los Angels", "Angel Stadium"),
    BallTeam("Athletics", "Oakland", "Oakland Coliseum"),
    BallTeam("Padres", "San Diego", "Petco Park")
    )
    // Truthにfilter機能がない?ので自分でfilterする
    // 一部の要素のみをみて比較する場合、Correspondenceを定義して行う
    // 比較する要素ごとにCorrespondenceの定義が必要になる
    val filterTarget = target.filter { team -> team.city.startsWith("San") }
    .filter { team -> team.city.endsWith("Francisco") }
    Truth.assertThat(filterTarget)
    .comparingElementsUsing(HAS_NAME)
    .containsExactly("Giants")
    val filterTarget2 = target.filter { team -> team.city == "Los Angels" }
    Truth.assertThat(filterTarget2)
    .comparingElementsUsing(BALLTEAM_NAME_PARSES_TO_TUPLE)
    .containsExactly(
    tuple("Dodgers", "Dodger Stadium"),
    tuple("Angels", "Angel Stadium")
    )

    View Slide

  14. 株式会社 ヤプリ
    株式会社 ヤプリ
    フィルタリング_truthの補⾜
    Copyright © 2019 Yappli, Inc. All rights reserved.
    13
    Truth
    private val HAS_NAME = Correspondence.transforming({ it?.name }, "Has an
    Name of")
    private val BALLTEAM_NAME_PARSES_TO_TUPLE = Correspondence.from(::ballteamParsesToTuple,
    "parses to")
    // Ballteamのnameとstadiumの⽐較
    private fun ballteamParsesToTuple(actual: BallTeam?, expected: Tuple?): Boolean {
    if (actual == null) {
    return expected == null
    }
    return expected?.toList()?.let { list ->
    if (list.isEmpty() || list.size != 2) return false
    actual.name == list[0] && actual.stadium == list[1]
    } ?: false
    }

    View Slide

  15. 株式会社 ヤプリ
    株式会社 ヤプリ
    例外の検証
    Copyright © 2019 Yappli, Inc. All rights reserved.
    14
    AssertJ
    Assertions.assertThatExceptionOfType(RuntimeException::class.java)
    .isThrownBy { functionMayThrow() }
    .withMessage("Aborted!")
    .withNoCause()

    View Slide

  16. 株式会社 ヤプリ
    株式会社 ヤプリ
    例外の検証
    Copyright © 2019 Yappli, Inc. All rights reserved.
    15
    Truth
    try {
    functionMayThrow()
    } catch (e: Throwable) {
    Truth.assertThat(e).apply {
    isInstanceOf(RuntimeException::class.java)
    hasMessageThat().contains("Aborted!")
    // withNoCause()
    }
    }

    View Slide

  17. 株式会社 ヤプリ
    株式会社 ヤプリ
    実際に動くテストコード
    Copyright © 2019 Yappli, Inc. All rights reserved.
    16
    スライドに記載したテストコードは発表⽤にガリガリ削ってます
    実際に動くものはGithubにて公開してます
    https://github.com/dais-33/android-truth

    View Slide

  18. 株式会社 ヤプリ
    株式会社 ヤプリ
    ⽐較してみた感想・結論
    Copyright © 2019 Yappli, Inc. All rights reserved.
    17
    • 流⽯にAssertJができることを全て網羅している訳ではない
    • ただし、必要最低限は網羅していそう
    Ø それはテストする必要があるのか︖という機能を削った印象

    すでにAssertJ等を使ってバリバリテストを書いてるアプリでは
    Truthに切り替える理由は薄い
    これからアサーションライブラリを導⼊しようと考えている場合は
    Truthも選択として⼗分有り

    View Slide

  19. 株式会社 ヤプリ
    株式会社 ヤプリ
    発表は以上になります。
    ご静聴ありがとうございました。
    Copyright © 2019 Yappli, Inc. All rights reserved.
    18

    View Slide