まとめ記事)Androidでテストをしたい【勉強編】
1 導入の経緯とざっと調べて躓いたこと
今、個人開発しているアプリがあるのですが、複雑な作りになってきたため、そろそろテストを導入しないと後々大変になるだろうなと思い、重たい腰を上げテストをすることにした。
最初にAndroidが公式で公開している「Testing in Jetpack Compose」[1]に取り組もうと、いざやってみるとBuildにとても時間がかかるし、沢山エラーが出て通らないので、もっと簡単なUIに対してテストする方法を、第三者が書いた記事をかき集めてやってみることにした(Buildに時間がかかるのは単純に、僕のパソコンがポンコツなのかもしれない…)。
とはいっても、初めて取り組むにはまず、テストの下調べをしないといけないので、Androidの公式ページを中心に調べたことを先に書いて、簡単なテストを実装していこうと思う(思ったよりもまとめが長くなってしまったので別記事にします)。
2 テストについて勉強する
アプリのテストを行うことで、沢山良いことがあります。早期にエラーを発見できたり、リファクタリングのときに便利らしいです(導入したことないので、本当化は体感的に、まだわからない)。
[3]
2.1 ざっくりとしたテストの種類(動作デバイス別)テストを動かすデバイスによって、大きく2つに大別することが出来る。
- ローカルJVM(Java Virtual Machine)で実行するJUnitテスト
- 実機デバイスまたはエミュレータで実行するインストルメンテーションテスト
実はVirtualの日本語は「仮想」ではない(豆知識)
記事を書きながらふと、頭をよぎったので、書こうと思います。最近流行りのバーチャルリアリティなど、よくバーチャルを「仮想」と訳して「仮想現実」と呼びますが、実は日本語的には誤訳(少なくとも適切ではない)と言われています。正確には本質的にほとんど等価なということをバーチャルといいます。実際に英和辞典で調べるとvirtualは事実上の、実質上のという日本語訳になっています[4]。もう、日本で「仮想現実」という言葉は用語として普及してしまっているので、名詞として捉えられると思いますが、virtualを「仮想」と訳すと大変なことになることがあります。
ちなみに、この件については、東京大学の廣瀬先生もスライド[5]で述べていますので、参考にしてください。
脱線していますが、「VR=バーチャルリアリティは, "仮想"現実か」という報告[6]も面白いので、ぜひ読んでみてください。
では、それぞれ、どのように使っていくのかを見ていく。
2.1.1 ローカルJVMで実行するJUnitテスト
これは、Androidフレームワークの依存関係がテスト対象に含まれていなかったり、含まれていたとしても、その依存関係がモックで代用できるときに使う。インストルメンテーションテストに比べて実行時間が速い。
2.1.2 デバイスなどで実行するインストルメンテーションテスト
このテストでは、テストコードでテスト対象のアプリを制御することでテストする方法。UIテストやJUnitテストでは出来ないテストを行う。
[2:1]
2.2 テストの基礎Android公式ページ[2:2]で重要そうなところを引用して、思ったことを書いていく。
[2:3]
2.2.1 テスト用にコードを編成するここの内容をざっくりいうと、開発中にテストをする「ユニットテスト」というものと、ユーザー視点に立ってテストする「モジュールテスト」というものがあるよということみたい。2、3回読んでもわからなかったので、この記事[7]を参考にしました。
2.2.1.1 ユニットテスト
ユニットごとに、対応する単体テストを作成します。単体テストでは、標準的な操作、無効な入力、リソースが利用できない場合の処理など、ユニットについて考えられるすべてのインタラクションをできる限りテストする必要があります。
つまり、これから実装しようと思っているユニットに対して、考えられるだけのインタラクションをテストするべきであるということだそうです。この記事[2:4]を読んだ感じ、あくまで実装したものにテストするという姿勢よりは、機能を定義して(テストを書いて)実装してテストするという姿勢らしい。次のモジュールテストと対象的に、こちらは作り手のロジックで各テストっぽい印象。
2.2.1.2 モジュールテスト
コードのテストを容易にするには、モジュールの観点に立ってコードを開発します。つまり、各モジュールは、ユーザーがアプリ内で実行する特定のタスクを表すものと考えます。
こちらは作り手のロジックというよりはユーザー目線に立ったテスト。ユーザーが行うタスク(メールを作成するとか、メールを受信するとか、削除するとか)ベースに考えるそうです。
2.2.2 テスト環境を構成する
Android Studioの初期に作成するプロジェクトには2つテストディレクトリがあって
- androidTest: デバイスでテストするコード
- test: ユニットテストなど、JVMで出来るもの
と使い分ける。
テストを実行する場合は、実際のデバイス、仮想デバイス、シュミレートされたデバイスのそれぞれに、メリットデメリットがあるので、よく考えて用いること(詳しくは公式ページ[2:5]を参照)
テストダブル(実際のオブジェクトではなく仮のオブジェクトのこと)を作成する方法は最終手段で、出来る限り実際のオブジェクトを利用したほうが良い。
2.2.3 テストを作成する
テストピラミッドという考え方があるらしく、小規模、中規模、大規模の3つに分けられる。
- 小規模テスト:各クラスごとに検証する単体テスト
- 中規模テスト:モジュール内またはモジュール間でのスタックレベルのインタラクションをテストする統合テスト
- 大規模テスト:ユーザーが実際に利用する過程を検証するエンドツーエンドテスト。
以下は作成時の注意点
2.2.3.1 小規模テスト
テストがAndroidフレームワークに依存する場合は、androidx.test APIなどのデバイスに依存しない統合APIを使用する(JVMに対応したマシンを常に利用しているのであればRobolectricも使用可)。
テストがリソースに依存する場合は、app/build.gradleファイルでincludeAndroidResourcesオプションを有効にする。
インストゥルメント単体テストは実行時間が大幅に遅くなるので、実際のデバイス、ハードウェアでのアプリ動作評価が必要な場合にのみ利用すること。
メインスレッドでテストを実行しないといけないときは @UiThreadTest アノテーションを付けること。
2.2.3.2 中規模テスト
対象となるのは
- ビューとビューモデル間のインタラクション
- レポジトリレイヤのテスト
- 特定の画面でのインタラクションのテスト(多分、ボタンを押したときに、各機能が発火するかどうかなど)
- マルチフラグメントテスト
これらのテストを実行するにはEspresso-IntentsライブラリやIntentSubjectとTruthベースのアサーションを組み合わせて使用する(実際に実装したときに詳しく書く)。
レポジトリレイヤとは〜どのように扱うべきか悩んでいること〜(つぶやき)
Jetpackのアプリアーキテクチャガイド[8]で
他の複数のクラスに依存するクラスはリポジトリのみです。
と書かれている。リポジトリは、単純にパイプする役割と思っていたのだが、リモートデータソースとモデルを統合して、あるタスクを行う一つのユニットとして扱うべきなのではないかなと最近思っているところです。つまり、ローカルのデータを引っ張ってきて、リモートのデータを引っ張ってきて、結合してViewModelに送るというような使い方をするのではないかなと思っています。
アサーションとは何か(用語)
アサーションとは何かわからなかったので、調べてみました。この記事[9]を参考にすると、ざっくり言えば、ある条件を満たさないときにエラーを吐かせる仕組みのようです。デバッグ時にはONにして、リリース時にOFFにすることで処理速度の向上も図れるようです。
ここからはつぶやきになりますが、実際に実装してみないと分からないので、実装してみて追記したいと思います。今の感覚的には、try catchのExceptionみたいな感じかなと勝手に思っています。
2.2.3.3 大規模テスト
一般的に実機よりも、エミュレータでアプリをテストするほうが適切。なぜなら、画面サイズとハードウェア構成の様々な組み合わせを簡単かつ迅速にテストできるから。[2:6]
ここでもEspressoを使う。長時間実行されるバックグラウンドオペレーションもトラッキングできるらしい。
2' ここまでのまとめ
長くなりそうなので、実装して実際に動かすのは別記事にします(ただのまとめ記事になってしまった)。
纏めとしては
- テストにはローカルJVMでテストする方法とデバイスでテストする方法がある
- ユニットテストは開発者ロジック、モジュールテストはユーザーロジックでテストする(多分)
- Android Studioのフォルダはテストする対象によって使い分ける
- 出来る限り実際のオブジェクトを使ってテストしたほうが良い
かなと思います。
今から、実際に実装してテストしてみたいなと思います。
この記事は、実装を通して、追記または修正していきたいと思います。
I 修正履歴
2021-12-23) 新規作成
-
Testing in Jetpack Compose / Android https://developer.android.com/codelabs/jetpack-compose-testing?hl=ja#0 (2021-12-23閲覧) ↩︎
-
テストの基礎 / Android https://developer.android.com/training/testing/fundamentals?hl=ja (2021-12-23閲覧) ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎
-
アプリをテストする / Android https://developer.android.com/studio/test?hl=ja (2021-12-23閲覧) ↩︎
-
デイリーコンサイス英和・和英辞典 第7版 ↩︎
-
リアルとバーチャル / 廣瀬通孝 https://ocw.u-tokyo.ac.jp/lecture_files/gf_18/5/notes/ja/05hirose.pdf (2021-12-23閲覧) ↩︎
-
VR=バーチャルリアリティーは、“仮想”現実か / 谷 卓生 , 放送研究と調査https://www.jstage.jst.go.jp/article/bunken/70/1/70_46/_pdf/-char/ja (2021-12-23閲覧) ↩︎
-
The Difference Between Unit Testing and Module Testing / jamesdmccaffrey https://jamesmccaffrey.wordpress.com/2008/08/29/the-difference-between-unit-testing-and-module-testing/ (2021-12-23閲覧) ↩︎
-
アプリ アーキテクチャ ガイド / Android https://developer.android.com/jetpack/guide?hl=ja (2021-12-23閲覧) ↩︎
-
プログラムの品質を高めるためのアサーションとは? / BULL https://atmarkit.itmedia.co.jp/ait/articles/0410/27/news115.html (2021-12-23閲覧) ↩︎
Discussion