Android Testing Frameworkを使ったUI操作のテストについて解説します。以下のサンプルを基に説明していきます。
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <EditText android:id="@+id/editer" android:layout_width="fill_parent" android:layout_height="wrap_content" /> <Button android:id="@+id/send" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/send" android:onClick="onTextUpdate" /> <TextView android:id="@+id/result" android:layout_width="fill_parent" android:layout_height="wrap_content" /> </LinearLayout>
public class HelloAndroidActivity extends Activity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } public void onTextUpdate(View v) { EditText edit = (EditText) v.getRootView().findViewById(R.id.editer); TextView text = (TextView) v.getRootView().findViewById(R.id.result); text.setText(edit.getText()); } }
上記は、テキストフィールドとボタンを用意して、ボタンをクリックしたらテキストフィールドに入力された文字列を「TextView」で表示させるという、単純なアプリケーションです。これを「ActivityInstrumentationTestCase2」クラスを使ってテストしていきます。
まずは、初期条件を確認します。テキストフィールドに何も入力されていないことと、TextViewに何も表示されていないことを確認してみます。
public void testEditText_initialize() throws Exception { EditText edit = (EditText)activity.findViewById(com.example.atec.ui.R.id.editer); TextView result = (TextView)activity.findViewById(ccom.example.atec.ui.R.id.result); assertEquals(“初期値は空文字”, "", edit.getText().toString()); assertEquals(“初期値は空文字”, "", result.getText()); }
次に、テキストフィールドに文字列を入力しButtonをクリックしたら、テキストフィールドの値を更新することを確認します。
特に、このサンプルではレイアウトでonClick()メソッドを指定しています。もしメソッド名を間違えても、コンパイル時には判断できず不安が残ります。正しいメソッド名を記述しているかどうかを確認するテストは自動化しておく価値があります。
public void testEditText_checkInput() throws Exception { final EditText edit = (EditText)activity.findViewById(com.example.atec.ui.R.id.editer); final Button button = (Button)activity.findViewById(com.example.atec.ui.R.id.send); TextView result = (TextView)activity.findViewById(com.example.atec.ui.R.id.result); activity.runOnUiThread(new Runnable() { @Override public void run() { edit.requestFocus(); // EditTextにフォーカスを当てる } }); instrumentation.waitForIdleSync(); // sendKeysで文字列を入力する sendKeys(KeyEvent.KEYCODE_F); sendKeys(KeyEvent.KEYCODE_O); sendKeys(KeyEvent.KEYCODE_X); activity.runOnUiThread(new Runnable() { @Override public void run() { button.performClick(); } }); instrumentation.waitForIdleSync(); assertEquals("入力された値は正しい","fox", result.getText().toString()); }
ここでは、「EditText」に入力された文字列を、正しいかどうかチェックしています。ここでは、文字列入力にInstrumentationTestCase#sendKey()を使いましたが、EditTextのsetText()を使ってもいいと思います。
ここで気を付けなければいけないのが、Androidは描画やUI操作を、「UIスレッド」という特別なスレッドで実行しているという点です。Androidのテストは、UIスレッドとは別のスレッドで実行されるため、UIに関する処理は、UIスレッドに処理をお願いしなくてはいけません。
runOnUiThread()は、引数で渡したRunnable実装クラスの処理を、UIスレッドで行ってもらうためのメソッドです。runOnUiThreadを呼んだ後、Instrumentation#waitForIdleSync()によってUIスレッドの処理が完了するまで待ってから、後続の処理を行うようにします。
今回は、正常系のテストのみ行いました。実際の開発は、境界値を考えて文字を入力しない場合や、入力可能な文字列以上の文字列を入力してしまう場合、特殊な文字を入力する場合をテストしておいた方がいいと思います。
同値分割や境界値分析の考え方を基に、テストケースを考えてみてください。
先ほどのテストを、「TouchUtils」というクラスを使った方法で書き換えてみます。これは、メソッドを直接実行するのではなく、ユーザー操作をエミュレートするためのクラスです。
public void testEditText_checkButtonClick() throws Exception { EditText edit = (EditText)activity.findViewById(com.example.atec.ui.R.id.editer); Button button = (Button)activity.findViewById(com.example.atec.ui.R.id.send); TextView result = (TextView)activity.findViewById(com.example.atec.ui.R.id.result); TouchUtils.clickView(this, edit); sendKeys(KeyEvent.KEYCODE_C); sendKeys(KeyEvent.KEYCODE_O); sendKeys(KeyEvent.KEYCODE_W); TouchUtils.clickView(this, button); assertEquals("ボタンがクリックされた時の値のチェック", "cow", result.getText().toString()); }
こちらの書き方の方が、UIスレッドを意識しないで書けるので、すっきりとします。
TouchUtilsはタップやスクロールのような操作のエミュレートがメソッドとして提供されています。ドキュメントを参考にしながら、ぜひいろいろ試してみてください。次ページでは、残りの2種のテストについて解説します
Copyright © ITmedia, Inc. All Rights Reserved.