スキップしてメイン コンテンツに移動

Mockitoを使ってActivityの分岐のテスト

テスト内容

Webサービス等のAPIを使って、ログイン未ならログイン画面をログイン済みならホーム画面を表示するようなAndroidアプリを考えます。このアプリのユニットテストを行うにあたり、ログイン状態の取得やWebサービスへアクセスするなどの実際の処理は行わないで、仮の実装でログイン未を返す場合とログイン済みを返す場合のテストケースを作成して、画面が遷移するかを確認できるようにしたいと思います。

テストはActivityUnitTestCaseで行います。この時、画面遷移の分岐をonCreateでやるか、onStartでやるかで変ってくるので、その2つについてサンプルを作成しました。

テストプロジェクトの準備

まず、本アプリのAndroidプロジェクトを作成後、Androidのテストプロジェクトを作成します。テストプロジェクトは
(アプリ側のパッケージ名).test
というようなパッケージができるのですが、このtest部分は消してアプリ側と同じパッケージ名にします。こうする事でアプリ側に定義されているデフォルトのアクセス修飾子にアクセスできるので、フィールドの変数の差し替えがやりやすくなります。(publicである必要がない)
※これ一つ知らないだけで、不必要にpublic変数にするなどだいぶテストの書き方に頭を悩ませてました...orz
参考文献:JUnit実践入門 ~体系的に学ぶユニットテストの技法 (WEB+DB PRESS plus)

libsには以下のものを配置します。詳細については割愛します。
  • dexmaker-1.0.jar
  • dexmaker-mockito-1.0.jar
  • hamcrest-all-1.3.jar
  • junit-4.11.jar
  • mockito-core-1.9.5.jar
  • com.springsource.org.objenesis-1.2.0.jar
※hamcrest-all-1.3.jarとmockito-all-1.9.5.jarを一緒にするとMultiple dex files defineというエラーが出るので、mockito-core-1.9.5.jarとcom.springsource.org.objenesis-1.2.0.jarの組み合わせです。

WebサービスのAPI部分

API部分はまだ実装していなくてもインタフェースを定義することでテストが行えます。
このようなインタフェースを設けます。このメソッドの結果でログイン未/済を判定するものとします。

ActivityのonStart()内に分岐の処理を設ける場合

Activityのフィールドに先ほどのインタフェースを定義しておきます。onStartでログイン未/済を判定します。

インターフェースの中身はまだ実装していない前提なのでnullにしています。当然ながらこのままアプリを起動するとNullPointerExceptionが発生します。

テスト側

ActivityUnitTestCaseではstartActivity()を実行するとActivityのonCreate()が実行されます。その後に、Activityのフィールドをテスト用に差し替えて、onStart()を動かしてテストを行います。テスト用はMockitoのmockにして戻り値を指定しています。
コード内のコメントでだいたいの流れはわかるかと思います。ちなみに、検証しているxmlはこんな感じです。

ActivityのonCreate()内に分岐の処理を設ける場合1

まずは、ActivityのonCreate()で分岐するコード(MainActivity2)はこんな感じでしょう。

テスト側

onStartと何が違うかと申しますと、ActivityUnitTestCaseのテストケースでActivityオブジェクトの取得がstartActivity()なのですが、そのタイミングでonCreate()も実行されるので、このままでは事前にmock版の差し替えを行うことができません。シンプルに考えると、startActivity()をオーバーライドしてonCreateしている所を除いて、しかるべきタイミングでonCreateを叩けばいいのですが、これが一筋縄にはいきません。AndroidのソースのActivityUnitTestCase.javaを参考にしながら書くとこんな感じになります。
startActivity()を再現するために、priavteなクラスのMockParentなどを追加しています。また、プライベートフィールドもあるのですが、省いてるので厳密にonCreate()だけ取り除いたというわけではありません。MyApplicationというのは、android.app.Applicationを継承したものです(アプリ側のManifestにも記述してます)。別途ActivityUnitTestCaseを継承したようなクラスを作成した方がコードが見やすくなるかもしれませんね。

ActivityのonCreate()内に分岐の処理を設ける場合2

もうひとつ考えたのが、MyApplicationにServerAPIsのフィールドを設けて、それをonCreate()で利用するやり方です。テストケースのsetApplicationする前にmock版に差し替えて、startActivity()すれば、差し替えたMyApplicationを参照するのでテストを行う事ができます。一応コードはこのような感じに。
コードはシンプルになるのですが、アプリ側のコードをテスト用にカスタマイズするのでアレですね。

参考文献

Androidのテストについて多くかかれているわけではないですが、テストの考え方でとても参考になりました。



コメント

このブログの人気の投稿

Javaでprivateなfieldやmethodにアクセスする

JUnitでテストしてると、privateなフィールドにアクセスして、値を参照したりセットしたりしたくなるわけですが、よく使うのでメモしておきます。 例えば、次のような対象のクラスがあるとします。 public class ParentClass { private String hoge = "ParentClass!!"; public void dispMsg() { System.out.println("dispMsg:" + hoge); } private void privateDispMsg(String msg) { System.out.println("dispMsg:" + msg); } }

GolangでWindows GUIアプリケーション

GUIアプリ作成の前提 社内ツールとしてexeで配布 開発環境はGoLandを使う 社内ツールとしてexeを配布ということであれば、Visual StudioでC#による開発だと思います。しかしながら、Go言語を習得したいのと、GoLandの補完機能が便利で、Android Studio使っていたこともあり、とっつきやすいという点からGo縛りでGUIアプリケーションを考えたいと思います。 lxn/walk Windows application library kit for Go. Windows向けしか考えていないので、まずこのライブラリなのですが、ボタンやコンボボックスが思ったように並ばなかったり、手軽にイメージボタンを配置したりなど、簡単にレイアウトを変更できない課題に直面しました。レイアウト作成だけで時間を取られてしまいます。そう言えば、Androidアプリ開発のときは、XMLでデザイン部分を切り離してたのを思い出して、今回の調査の運びとなりました。 fyne-io/fyne Cross platform native GUIs designed for Go based on Material Design. Supports: Linux, macOS, Windows, BSD, iOS and Android. walkと比べると、クロスプラットフォームで作成できるのですが、こちらもコードの中にデザインを書いていく形でした。 therecipe/qt therecipe/qt allows you to write Qt applications entirely in Go or JavaScript. Qt Creatorなるものがあるようで、デザイン部分を切り離せる印象はあるものの、最新のPCでもビルドに時間がかかるようで、学習コストもかかるという記事を見かけて断念しました。 どうしたものかとツイートしましたら、下記のようにご助言をいただいた。 同じ課題に対し色々試した結果、PWAのフルキャッシュドに落ち着いた。中身はGo+WASMで。 https://t.co/e60whDTV16 — のぼのぼ📡 (@nobonobo) July 21, 2020 PWA 早速調べてみました。Googleが進めているプロジェクトで、ネイティブアプリのよ

Eclipseの高速化メモ

Eclipseが重いと一言に言っても、いろいろな工程での話があると思いますが、過去記事のなども含めてこの記事にピックアップしておきたいと思います。以下はWindows環境での話です。