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

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

[宮田友美,日本Androidの会テスト部]
前のページへ 1|2|3       

AndroidTestCaseとモックを使ってテストを書く

 Androidからサーバアプリにアクセスするようなアプリを開発する場合、テスト用のサーバと本番用のサーバの設定を変更したいことがよくあります。AndroidTestCaseとモックオブジェクトを利用すると、テスト実行時に利用するリソースファイルを切り替えることも可能です。今回は、サーバへの接続情報を取得クラスに対するテストを記述していきます。

サンプルプロジェクト「BusinessLogicSample」

 ここでは、テスト対象プロジェクトとして「BusinessLogicSample」を用意しました。このプロジェクトを利用してテストを書いていくことにしましょう。

package com.example.atec.business;
 
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
 
import android.content.Context;
import android.text.TextUtils;
import android.util.Log;
 
public class SecretResource {
    private static final String TAG = "ATEC";
    private String twitterConsumer;
    private String twitterSecret;
    
    public String getTwitterConsumer() {
        return twitterConsumer;
    }
    public String getTwitterSecret() {
        return twitterSecret;
    }
    public boolean isAvailable() {
        return !TextUtils.isEmpty(twitterConsumer) && !TextUtils.isEmpty(twitterSecret);
    }
    public static SecretResource load(Context context, int resourceId) {
        SecretResource secretResource = new SecretResource();
        InputStream in = context.getResources().openRawResource(resourceId);
        try {
            Properties prop = new Properties();
            prop.load(in);
            secretResource.twitterConsumer = prop.getProperty("twitter.consumer");
            secretResource.twitterSecret = prop.getProperty("twitter.secret");
        } catch (IOException e) {
            Log.w(TAG, "properties load error", e);
        } finally {
            try {
                in.close();
            } catch (IOException e) {
            }
        } 
        return secretResource;
    }
}
src/com/example/atec/business/SecretResource.java

 SecretResources.javaは「config.properties」からサーバへの接続情報を読み込んで保持するクラスです。

twitter.consumer=consumer_key
twitter.secret=secret_key
res/raw/config.properties

 config.propertiesにはサーバへの接続情報が設定されています。

 テストプロジェクトに以下のファイルを作成します。

  • プロジェクト名:BusinessLogicSampleTest
  • ファイルの場所:src/com/example/atec/business/SecretResourceTest.java

AndroidTestCaseを拡張

 まず、ServerConfigTestクラスを作成します。このクラスはAndroidTestCaseを拡張させます。

public class SecretResourceTest extends AndroidTestCase {
}
SecretResourceTest.java

モックのリソースクラスを定義

 config.propertiesファイルを読み込む代わりに、テスト中で定義した文字列をInputStreamとして返すよう実装します。「MockResources」の拡張クラスTestResourcesは、例外を投げるだけなので、ここで必要なopenRawResources()だけをオーバーライドして使用します。

public class SecretResourceTest extends AndroidTestCase {
    class TestResources extends MockResources {
        @Override
        public InputStream openRawResource(int id)
                throws NotFoundException {
            byte[] buf = "twitter.consumer=11111\ntwitter.secret=22222"
                    .getBytes();
            InputStream in = new ByteArrayInputStream(buf);
            return in;
        }
    }
}
SecretResourceTest.java

モックのコンテキストクラスを定義

 先ほど定義したモックのリソースクラスを返すコンテキストを実装します。「MockContext」クラスの拡張クラスも例外を投げるだけとなっています。テストで必要なgetResources()のみオーバーライドします。


class TestContext extends MockContext {
    @Override
    public Resources getResources() {
        return new TestResources();
    }
}
SecretResourceTest.java

 さらに、setContext()を利用してモックのコンテキストを設定します。ここではsetUp()メソッド内でモックコンテキストを設定し、テストメソッドでgetContext()を呼び出すことでモックのコンテキストを取得しています。

テスト実行

 そして、テストメソッドを記述し、TestResourcesで定義した値が取得できているかテストします。 「twitter.consumer=11111」「twitter.secret=22222」が期待値となりますので、テスト結果が同様の値となればテストは成功です。


@Override
protected void setUp() throws Exception {
    super.setUp();
    setContext(new TestContext());
}
public void testLoad() throws Exception {
    SecretResource resource = SecretResource.load(getContext(), R.raw.config);
    assertNotNull(resource);
    assertEquals("consumer key", "11111", resource.getTwitterConsumer());
    assertEquals("secret key", "22222", resource.getTwitterSecret());
}
SecretResourceTest.java
package com.example.atec.business;
 
import java.io.ByteArrayInputStream;
import java.io.InputStream;
 
import android.content.res.Resources;
import android.test.AndroidTestCase;
import android.test.mock.MockContext;
import android.test.mock.MockResources;
 
import com.example.atec.business.test.R;
 
public class SecretResourceTest extends AndroidTestCase {
    /*
     * (non-Javadoc)
     * 
     * @see android.test.AndroidTestCase#setUp()
     */
    @Override
    protected void setUp() throws Exception {
        super.setUp();
        // モックのコンテキストを設定
        setContext(new TestContext());
    }
 
    /**
     * config.properties読み込みのテスト
     * 
     * @throws Exception
     */
    public void testLoad() throws Exception {
        // config.properties読み込み
        SecretResource resource = SecretResource.load(getContext(),
                R.raw.config);
        assertNotNull(resource);
        assertEquals("consumer key", "11111", resource.getTwitterConsumer());
        assertEquals("secret key", "22222", resource.getTwitterSecret());
    }
 
    /**
     * MockResourcesを返すContext
     */
    class TestContext extends MockContext {
 
        /*
         * (non-Javadoc)
         * 
         * @see android.test.mock.MockContext#getResources()
         */
        @Override
        public Resources getResources() {
            return new TestResources();
        }
    }
    /**
     * 文字列からリソースを返すMockResources
     */
    class TestResources extends MockResources {
        /*
         * (non-Javadoc)
         * @see android.test.mock.MockResources#openRawResource(int)
         */
        @Override
        public InputStream openRawResource(int id)
                throws NotFoundException {
            byte[] buf = "twitter.consumer=11111\ntwitter.secret=22222"
                    .getBytes();
            InputStream in = new ByteArrayInputStream(buf);
            return in;
        }
    }
}
※SecretResourceTest.java全体のソース

 テストを実行し、グリーンーバーが表示されるかを確認します。

モックオブジェクトを使う利点

 このようにモックオブジェクトを利用すると、実際にアプリを動かす場合とテストを実行する場合で環境を切り替えたい場合に、テスト対象プロジェクトのソースコードなどを変えることなくテスト用の環境に切り替えることができます。

コラム Twitterクライアントに対するテスト「testter」

このサンプルは、テスト部で作成している「testter」というTwitterクライアントに対するテストから抜粋したものです。

testterはテスト部でテストを書く対象のために作成したAndroidアプリです。ソースコードも公開されていますのでぜひ1度ご覧ください。


次回は、UIのテストケースの書き方

 さて、今回のビジネスロジックのテストはいかがだったでしょうか。ビジネスロジックのテストケースを記述することで、ビジネスロジックがAndroid固有のコンポーネントから自然と分離されるようになります。そうすると、記述が面倒なAndroid固有のコンポーネントにかかわる処理のテストケースが自然と減ります。ぜひAndroidアプリのビジネスロジックテストを自動化してみてください。

 また、本稿で掲載したソースコードは以下のリポジトリで公開されています。

  • https://atec.googlecode.com/svn/atmarkit/businesslogic/trunk/BusinessLogicSample
  • https://atec.googlecode.com/svn/atmarkit/businesslogic/trunk/BusinessLogicSampleTest

 次回は、Androidテスト部で議論にのぼることが多いUIのテストケースの書き方について解説します。ご期待ください。

著者紹介

Androidテスト部部長

宮田友美

株式会社オープンストリームにおいて、アーキテクトとしてAndroidの調査・研究および案件支援に従事。趣味はAndroid系端末をはじめとしたガジェット収集。しかし最近は、心踊るガジェットが最近あまり発売されないのが悩みの種



前のページへ 1|2|3       

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

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

メールマガジン登録

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