連載
» 2011年12月16日 00時00分 公開

Android SDKでビジネスロジックのテストを自動化するにはAndroidアプリ開発テスト入門(2)(2/3 ページ)

[宮田友美,日本Androidの会テスト部]

Android SDKが提供するTestCase

 前述のとおり、Android SDKでは「TestCase」クラスの拡張クラスが用意されています。それぞれの拡張クラスはAndroidのコンポーネントのテストをしやすいように拡張されていますので、テスト対象や用途によって使い分けます。

 TestCaseクラスを拡張した、「InstrumentationTestCase」「AndroidTestCase」の2つの基底クラスがあり、そのどちらかを拡張したTestCaseがいくつか用意されています。

 InstrumentationTestCaseはその名の通り、Instrumentationのインスタンスを持つTestCaseです。Instrumentationは、Androidのシステムをフックしたり、制御するメソッドの集まりです。アクティビティにキーイベントも送信できます。

 一方のAndroidTestCaseはリソースや、コンテキストに依存するものにアクセスする必要がある場合に利用します。キーイベントの送信などはできません。

 システムのフックや制御、キーイベントの送信が必要なく、リソースやコンテキストに依存しないテストケースの場合は、TestCaseクラスを拡張してテストを記述可能です。

アクティビティのテスト

 アクティビティのテストを記述するために、以下の3つの拡張クラスが提供されています。

  1. ActivityInstrumentationTestCase2
  2. ActivityUnitTestCase
  3. SingleLaunchActivityTestCase

 上記クラスの基底クラスはInstrumentationTestCaseとなっています。InstrumentationTestCaseでは、「ライフサイクルの制御」や、「DI」機能を実現しています。

 「ライフサイクルの制御」とは、テスト対象のActivityの開始、一時停止、破棄を制御できるということです。

 DI機能では、ContextやApplicationのモックオブジェクトを生成し、そのモックオブジェクトを差し込んでアクティビティを実行できます。また、テスト対象のアクティビティにキーイベントやタッチイベントも送信可能です。

 モックオブジェクトについては、後程サンプルソースを交えて説明します。

 アクティビティのために拡張されたTestCaseは、それぞれ以下のように使い分けます。

  • ActivityInstrumentationTestCase2

 主に機能テスト(システムテスト、受け入れテスト)での使用を想定したTestCaseです。先ほど、InstrumentationTestCaseではモックオブジェクトを差し込めると記述しましたが、ActivityInstrumentationTestCase2では、この機能を利用できません。モックオブジェクトを差し込みたい場合は後述のActivityUnitTestCaseを利用します。

 getActivity()メソッドを実行すると、テスト対象のアクティビティのライフサイクル(onCreate()、onStart()、onResume())が開始されます。ライフサイクルは、これらのメソッドを呼び出すたびに開始され、アクティビティのインスタンスも別のインスタンスが戻されます。

 なお、SingleLaunchActivityTestCaseでは、getActivity()を実行すると毎回同じインスタンスのアクティビティが返されます。

 また、ActivityInstrumentationTestCase2では、setActivityIntent()を利用して、モックのインテント(Intent)をテスト対象のアクティビティに送信できます。このため、インテントにアクティビティが正しく応答しているか、また、インテントで渡されるデータを正しく受け取れているかのテストを記述できます。

  • ActivityUnitTestCase

 ActivityUnitTestCaseは、モックのContextやApplicationを差し込むことができます。このため、テスト用の独立した環境を設定し、その環境下でアクティビティがどのように振るうかをテスト可能です。

 アクティビティの取得には、startActivity(Intent intent, Bundle savedInstanceState, Object lastNonConfigurationInstance)メソッドを利用します。

 ただし、ActivityInstrumentationTestCase2と違ってonCreate()が呼び出されるのみで、onStart()、onResume()は呼び出されません。つまり、各ライフサイクルを手動で呼び出すことになります。ライフサイクルで呼び出されるコールバックのテストを記述する場合はActivityUnitTestCaseを利用します。

 また、startActivity()を実行前にgetAcitivity()を呼び出してもアクティビティを取得できないため、注意が必要です。startActivity()実行後はインスタンスを取得できますが、アクティビティのライフサイクルは開始されません。

 もう1つ注意すべき点は、テスト対象のアクティビティから他のアクティビティを実際には開始できないということです。テスト対象のアクティビティ内でActivity#startActivity()やActivity#startActivityForResult()を実行してもアクティビティは起動しません。

 その代わり、それらのメソッドを利用して呼び出されるアクティビティのインテントや、アクティビティから戻されるリクエストコードをgetStartedActivityIntent()getStartedActivityRequest ()から取得可能です。

 ActivityUnitTestCaseを利用したテストは、テスト対象のアクティビティ単体に閉じたテストを書く際に利用します。

コンテンツプロバイダのテスト

 コンテンツプロバイダをテストするために、「ProviderTestCase2」が提供されています。ProviderTestCase2は、「IsolatedContext」「MockConentResolver」を利用することにより、テスト実行時に独立した環境下でテスト可能です。

 つまり、テストメソッド内でデータの追加・削除をしても、他のテストメソッドに影響を与えません。そのため、簡単にコンテンツプロバイダのテストを記述可能です。

サービスのテスト

 サービスのテストは「ServiceTestCase」を利用して記述します。「MockApplication」「MockContext」を差し込むことが可能です。

 またServiceTestCaseは、startService()bindService()といったメソッドを提供しており、これらのメソッドが呼び出されるまでテスト対象のサービスのライフサイクルは開始されません。

その他のテスト

 その他のテストはTestCaseまたはAndroidTestCaseを利用して記述します。

 AndroidTestCaseはリソースにアクセスする必要がある場合や、パーミッションのテストを記述する必要がある場合に利用します。Androidのリソースなどにアクセスする必要がないようなテストはTestCaseクラスを拡張してテストを記述します。

TestCaseを使ってビジネスロジックのテストを書く

 Androidアプリのビジネスロジックは、AndroidTestCaseやTestCaseクラスを利用して記述します。今回は、「StringUtils」というサンプルクラスに対してTestCaseクラスを利用してテストメソッドを記述してみましょう。

サンプルクラス「StringUtils」

 StringUtilsは文字列の処理のためのユーティリティクラスです。渡されたCharSequenceがnullまたは空文字もしくはスペースのみの場合は「true」、そうでない場合は「false」を返すメソッドです。

public class StringUtils {
    public static boolean isBlank(CharSequence cs) {
        int strLen;
        if (cs == null || (strLen = cs.length()) == 0) {
            return true;
        }
        for (int i = 0; i < strLen; i++) {
            if (!Character.isWhitespace(cs.charAt(i))) {
                return false;
            }
        }
        return true;
    }
}
StringUtils.java

テストクラスの作成

 このクラスに対してテストを記述します。テストクラスの作成方法は連載第1回を参照してください。このクラスのテストにはAndroidのリソースやコンテキストは必要ないため、通常のJavaのテストと同様にjunit.framework.TestCaseを拡張してテストクラスを作成します。

import junit.framework.TestCase;
 
public class StringUtilsTest extends TestCase {
}
StringUtilsTest.java

テストメソッドの作成

 テストメソッドを記述したい位置に「test」と記述して[Ctrl]+[Space]キーで「test − test method」を選択し、テストメソッドのスタブを生成します。

 生成したテストメソッドを以下のように書き換えます。

public class StringUtilsTest extends TestCase {
    public void testIsBlank() throws Exception {
        assertTrue(StringUtils.isBlank(null));
        assertTrue(StringUtils.isBlank(""));
        assertTrue(StringUtils.isBlank(" "));
        assertFalse(StringUtils.isBlank("bob"));
        assertFalse(StringUtils.isBlank("  bob  "));
    }
}
StringUtilsTest.java

テスト実行

 テストを実行すると、[JUnit]ビューが表示され、グリーンバーが表示されるはずです。

 このように、Androidのリソースやコンテキストに依存しないロジックのテストはTestCaseクラスを利用すると、通常のJUnitと同じようにテストを記述可能です。

 続いて次ページでは、AndroidTestCaseとモックオブジェクトを使ってビジネスロジックのテストを書いていきます。

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。