日本Androidの会テスト部が、いままで培ってきたAndroidアプリ開発におけるテストのノウハウを、実際のテストコード例とともに紹介していきます
本連載「Androidアプリ開発テスト入門」では、Androidアプリを開発している方のためにテストの基本的なノウハウを解説しています。第5回では、Android Mockを利用したテストについて解説します。
本記事で紹介しているAndroid Mockは、2012年11月に開発・サポートの終了を宣言されました。より一般的な下記モックフレームワークのDalvik仮想マシン対応がほぼ完了しており、その役目を終えたためです。
新規に作成するプロジェクトでは、これら他のモックフレームワークを使用することをお勧めします。@ITでは、他のモックフレームワーク導入方法を紹介する記事を掲載予定です。
なお、本記事のサンプルコードをMockito向けに書き換えたものを公開しています。以下をご参照ください。
さらに、EasyMock向けに書き換えたものも公開しています。
第4回の「スマホアプリに必須なデータ永続化のためのDBテスト」では、データベース内部のデータによって実行結果が影響を受けず、常に同じ実行結果を得る工夫をすることによってテストの自動化を実現しました。
それでは、Android端末の外に存在するWebサーバとの通信を伴う処理のテストはどのように自動化すべきでしょうか。外部のWebサーバが常に理想的なレスポンスを返してくれるとは限りませんし、異常系のテストも必要です。常に固定レスポンスを返すテスト専用サーバを立てることも可能ですが、テストと連動させるのは複雑であり、構築にコストが掛かってしまいます。
この問題を解決するため、「モックオブジェクト」というテクニックがあります。例えば、HTTP通信では実際にWebサーバと通信するのは「org.apache.http.client.HttpClient」実装クラスのインスタンスですが、これを「モック(偽の)」オブジェクトに置き換えます。
そして、「HttpClient#execute()」メソッドの戻り値をあたかも通信が失敗したように、もしくは成功したように振る舞うことで、実際にはWebサーバとまったく通信することなく製品コード(HttpClientを使うメソッドのコード)をテストできます。
モックオブジェクトについては、連載第2回「Androidでビジネスロジックのテストを自動化するには」で「android.test.mock.MockContext」のサブクラスを定義し特定メソッドをオーバーライドする方法を紹介しています。
しかし、テストケースごとに振る舞いの違うサブクラスを定義するのは大変なので、多くの言語向けにモッククラスを動的に生成するフレームワークが開発されています。そのうち、Java向けの「EasyMock」(2.4)をAndroid(DalvikVM)上で実行できるようにラップしたものがAndroid Mockです。
Javaだけでも、EasyMockのほか、「PowerMock」「JMockit」「Mockito」などが存在しますが、そのままAndroid(Dalvik仮想マシン)上では使えません。
ただ、2012年2月時点でMockitoにはAndroidをサポートするパッチが作られているため、近い将来、正式に使えるようになるかもしれません。Mockitoについては、以下の記事を参照してください。
まずはコード例をご覧ください。HttpClientでWebサーバからフィードを取得するメソッド(リスト1)に対し、HttpClient#execute()が例外をスローするケースのテストコード(リスト2)です。
これは、Webサーバからステータスコード200(OK)が返ったときにはレスポンス本文のInputStreamを返し、それ以外のコードではInvalidHttpStatusCodeExceptionを返すメソッドです。
「@UsesMocks」というアノテーションとAndroidMockクラスが特徴的です。これによってHttpClientのモックオブジェクトを動的に生成できます。
*1の行では、モックのHttpClientに対し、「execute()」メソッドは引数の内容を問わず(notNull)例外expectedをスローすることを定義しています。
*2の行では、AndroidMock#replay()によって定義したモックオブジェクトの振る舞いが有効になります。
*3の行では、テスト対象のインスタンスが保持するHttpClient(mHttpclient)をモックオブジェクトに差し替えます。
これを実行すると、モックオブジェクトの振る舞いによって「FxRateLoader#requestFeed()」内部から「UnknownHostException」がスローされます。このテストは正しくパスしたといえるでしょう。
「AndroidMock.expect()」にはさまざまな書式があり、引数を厳密に判定したり、複雑な振る舞いを持たせることも可能です。詳細はAndroid MockプロジェクトWikiにある「WritingTestsUsingAndroidMock」をご覧ください。
Copyright © ITmedia, Inc. All Rights Reserved.