あいさつ
高畑です。最近何も考えずにソースコードを書き始めると怒られます・・・
高畑です。なぜかif文を書くと土下座しろと怒られます・・・
高畑です・・・高畑です・・・高畑です・・・
というわけで、お久しぶりです高畑です。
今回はAndroidのActivityのライフサイクルをテストするサンプルを紹介したいと思います。
Androidの自動テストについて
まず、Activityのテストの説明の前にAndroidの自動テストについて簡単に説明します。
大雑把に分けてAndroidの自動テストには以下の三つがあります。
テストケース |
説明 |
mock |
---|---|---|
ActivityInstrumentationTestCase2 |
UIの動作も含めたテストを行う |
× |
InstrumentationTestCase |
クラスの単体テスト |
○ |
ActivityUnitTestCase |
Activity単体のテスト |
○ |
今回説明するのは3番目のActivityの単体テストです。
2番目のInstrumentationTestCaseでクラスの単体テストを行う方法はこちらを参考にしてください。
準備
今回は単体テストを通すためのmockとしてmockitoを使います。
mockitoとは、Javaの開発でよく利用される、シンプルかつ強力なmockライブラリです。
Androidの開発でmockitoを使うためにはmockitoのライブラリを単にクラスパスに追加するだけでは動いてくれないので、dexmakerというライブラリを使用します。
dexmakerとは
android junit testでmockitoを使うためのサポートクラスが入っているとこちらに書いてあります。
mockitoだけでもコンパイルは通るのですが、実際にmockitoを使うとExceptionが発生してしまうので、dexmarkerの追加は必ず必要になります。
実際にmockitoを導入する手順は以下になります
1.dexmakerのサイトからdexmaker-1.0.jarとdexmaker-mockito-1.0.jarをダウンロードする
2.mockitoのサイトからmockitoをダウンロードする
3.ダウンロードしてきたjarをAndroidテストプロジェクトのライブラリに追加する
以上で準備は完了です。
テスト対象となるActivityのサンプルソース
このActivityはintentでArrayListを受け取って、各ライフサイクルでTextViewにArrayListから取得した文字列をセットするのとonClickリスナーを実装したActivityです。
詳しくはソース中のコメントに記載していますのでご覧ください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
public class HogeActivity extends Activity implements View.OnClickListener { private ArrayList<String> list = null; private Button button1 = null; private Button button2 = null; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); //intentでarrayListを受け取ってTextViewに文字列を設定する list = getIntent().getStringArrayListExtra("list"); ((TextView)findViewById(R.id.text)).setText(list.get(0)); //button1,button2にclickListenerをセットする button1 = (Button) findViewById(R.id.button1); button2 = (Button) findViewById(R.id.button2); button1.setOnClickListener(this); button2.setOnClickListener(this); } @Override public void onStart(){ super.onStart(); //list.get(1)で取得した文字列をTextViewにセットする ((TextView)findViewById(R.id.text)).setText(list.get(1)); } @Override public void onResume(){ super.onResume(); //list.get(2)で取得した文字列をTextViewにセットする ((TextView)findViewById(R.id.text)).setText(list.get(2)); } @Override //button1,button2を押したときのclickListener public void onClick(View view) { //clickされたボタンのIDで判定 if( view.getId() == R.id.button1 ){ doButton1(); }else if( view.getId() == R.id.button2 ){ doButton2(); } } //button1が押されたときに実行するメソッド public void doButton1(){ //doSomething } //button2が押されたときに実行するメソッド public void doButton2(){ //doSomething } } |
なんとも適当なActivityですが、このAcitivityの
onCreate(),onStart(),onResume(),onClick()についてのテストコードを書いてみます。
テストコード
こちらはActivityをテストするコードになります。
mockitoの使い方を簡単に説明すると
ArrayList
doReturn(“hoge”).when(mockList).get(0);と書くことでメソッドのスタブを作成できます。
この場合、mockListのget(0)が呼ばれた場合、”hoge”という文字列を返却することになります。
verify(mockList).get(0);と書くことでmockList.get(0)が呼ばれたことを確認します。
mockitoの詳しい使い方はこちらをご覧ください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
public class HogeActivityTest extends ActivityUnitTestCase<HogeActivity> { private HogeActivity target = null; public HogeActivityTest() { super(HogeActivity.class); } public void testHogeActivity(){ Intent intent = new Intent(); ArrayList<String> mockList = mock(ArrayList.class); //ArrayListクラスのmock作成 doReturn("hoge").when(mockList).get(0); //get(0)が呼ばれたとき"hoge"を返す doReturn("fuga").when(mockList).get(1); //get(1)が呼ばれたとき"fuga"を返す doReturn("foo").when(mockList).get(2); //get(2)が呼ばれたとき"foo"を返す intent.putStringArrayListExtra("list",mockList); //intentにArrayListのmockをputする //onCreateの処理をテスト target = startActivity(intent,null,null); target = spy(target); assertEquals("hoge",((TextView)target.findViewById(R.id.text)).getText());//TextViewにhogeがセットされていることを確認 verify(mockList).get(0); //mockList.get(0)が呼ばれたことを確認 //onStartの処理をテスト getInstrumentation().callActivityOnStart(target); assertEquals("fuga",((TextView)target.findViewById(R.id.text)).getText());//TextViewにfugaがセットされていることを確認 verify(mockList).get(1); //mockList.get(1)が呼ばれたことを確認 //onResumeの処理のテスト getInstrumentation().callActivityOnResume(target); assertEquals("foo",((TextView)target.findViewById(R.id.text)).getText());//TextViewにfooがセットされていることを確認 verify(mockList).get(2); //mockList.get(2)が呼ばれたことを確認 //onClickのテスト doNothing().when(target).doButton1(); //doButton1()が呼ばれたとき何もしない doNothing().when(target).doButton2(); //doButton2()が呼ばれたとき何もしない View view = mock(View.class); //Viewクラスのmockを作成 doReturn(R.id.button1).when(view).getId();//viewのgetId()が呼ばれたとき、button1のIDを返す target.onClick(view); //onClickにmockのviewを引数として実行 verify(target).doButton1(); //doButton1()が呼ばれたことを確認 doReturn(R.id.button2).when(view).getId();//viewのgetId()が呼ばれたとき、button2のIDを返す target.onClick(view); //onClickにmockのviewを引数として実行 verify(target).doButton2(); //doButton2()が呼ばれたことを確認 } } |
後はAndroid JUnit Testを実行すれば、問題なくテストが通るはずです。
以上でAndroidでmockitoを使ったActivityの単体テストの説明は終了です。
この勢いでActivityInstrumentationTestCase2についても機会があれば書いてみたいですね。
iOSに浮気を始めたAndroidエンジニア? Androidはほとんど書いてない…