AndroidのテストツールNativedriverを使ってみる
サンプルプロジェクトをgithubに上げているので参照してください。
yyhayashi303/Sample_Nativedriver_App · GitHub
yyhayashi303/Sample_Nativedriver_Test · GitHub
環境構築
1.jarファイル取得
ライブラリはjarが配布されているわけではなく、上記のwikiに記載されているsvnからソースを落としてきてantでビルドする必要があります。
$ svn checkout https://nativedriver.googlecode.com/svn/trunk nativedriver --username {Google account e-mail address}
$ cd nativedriver/android $ ant
antを実行するとnativedriver/android/build/以下にjarが生成されます。そのうち、使用するのは下記の2つになります。
・server-standalone.jar
・client-standalone.jar
2.Androidプロジェクト作成
・テスト対象となるAndroidプロジェクトを作成し、server-standalone.jarをビルドパスに追加します。
・AndroidManifest.xmlに下記を追加
<instrumentation android:targetPackage="sample.nativedriver" android:name="com.google.android.testing.nativedriver.server.ServerInstrumentation" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
3.テストプロジェクト作成
・テストプロジェクトもAndroidプロジェクトと思いきや、通常のJavaプロジェクトを作成。
・ビルドパスにclient-standalone.jarとjUnit3を追加します。
以上で準備はOKです。
今回はとりあえず「画面遷移」と「ListViewの操作」をやってみます。
画面遷移のテスト
名前と年齢を入力すると遷移先の画面で「未成年」か「成人」かを判断して出力するActivityを作成します。
これをテストするテストクラスを作成します。
まず、コードを少し簡潔にするためにTestCaseクラスを拡張してNativedriverTestCaseクラスを作成しました。
NativedriverTestCase.java
package sample.nativedriver; import junit.framework.TestCase; import org.openqa.selenium.By; import com.google.android.testing.nativedriver.client.AndroidNativeDriver; import com.google.android.testing.nativedriver.client.AndroidNativeDriverBuilder; import com.google.android.testing.nativedriver.client.AndroidNativeElement; import com.google.android.testing.nativedriver.common.AndroidNativeBy; public abstract class NativedriverTestCase extends TestCase { protected AndroidNativeDriver driver; @Override protected void setUp() throws Exception { driver = new AndroidNativeDriverBuilder().withDefaultServer().build(); } @Override protected void tearDown() throws Exception { driver.quit(); } protected AndroidNativeElement findElementById(String id) { return findElement(By.id(id)); } protected AndroidNativeElement findElementByText(String text) { return findElement(AndroidNativeBy.text(text)); } protected AndroidNativeElement findElementByName(String name) { return findElement(AndroidNativeBy.name(name)); } protected void startActivity(String activityName) { driver.startActivity(activityName); } protected void back() { driver.navigate().back(); } private AndroidNativeElement findElement(By by) { return driver.findElement(by); } }
で、これがNativedriverTestCaseを継承したテストクラス
SimpleActivityTest.java
package sample.nativedriver; import com.google.android.testing.nativedriver.client.AndroidNativeElement; import com.google.android.testing.nativedriver.common.AndroidKeys; public class SimpleActivityTest extends NativedriverTestCase { public void testSubActivity() { startActivity("sample.nativedriver.SimpleActivity"); AndroidNativeElement editName = findElementById("edit_name"); editName.sendKeys("yyhayashi303"); AndroidNativeElement editAge = findElementById("edit_age"); // フォーカスを当てるためにクリックする必要がある editAge.click(); editAge.sendKeys("27"); driver.getKeyboard().sendKeys(AndroidKeys.ENTER); findElementById("transit_next").click(); assertEquals("yyhayashi303さんは成人です。", findElementById("profile").getText()); } }
コメントにもあるように、click()メソッドを呼んでおかないとeditAge.sendKeys("27")としているのにも関わらず、editNameに入力されてしまうので注意が必要。
テスト実行
実行方法がなかなか面倒で下記の手順で行う必要があります。
1.Androidアプリインストール
Androidプロジェクトを右クリック → Run As → Android Application
2.テストのリクエストを受けるデバイスの準備
コンソールから下記のコマンドを実行します。
sample.nativedriverの部分は、AndroidManifest.xmlに追加したinstrumentationのtargetPackageと同じものを指定します。
adb shell am instrument sample.nativedriver/com.google.android.testing.nativedriver.server.ServerInstrumentation
NativedriverからのTCP接続を有効化します。
adb forward tcp:54129 tcp:54129
3.テストプロジェクト実行
テストプロジェクトを右クリック → Run As → JUnit Test
これでテストが実行出来たと思います。
上記手順の2についてですが、テストをしていてアプリが落ちてしまったりした場合は、再度コンソールからコマンドを実行しなければいけないのでとても面倒です。
しかし、Wikiに下記のような記述があり、将来的にはコードから実行できるようになるようです。
In the future these steps should be done through code, maybe using an extended AdbConnection class. For now, this part must be done manually:
ListViewの操作
ListViewのアイテムをクリックすると、その文字が一番したのTextViewに表示されるというものです。
テストクラスは下記になります。
SimpleListActivityTest.java
package sample.nativedriver; public class SimpleListActivityTest extends NativedriverTestCase { public void testOnItemClick() { startActivity("sample.nativedriver.SimpleListActivity"); String[] array = new String[] { "java", "javascript", "python", "ruby", "perl", "scala"}; for (String text : array) { // 指定リストをクリック findElementById("list").findElementByText(text).click(); // 少し待たないと下記のチェックでselectedの値が取得できない... w(200); // 選択されたアイテムが正しいかチェック assertEquals(text, findElementById("selected").getText()); } } private void w(long time) { synchronized (this) { try { wait(time); } catch (InterruptedException e) { throw new RuntimeException(e); } } } }
ListViewの場合、各アイテムにidが無いのでtextとして設定されている文字列でAndroidNativeElementを取得するしかなく、汎用的にテストを書くことができませんでした。。
ListViewの全要素を取得できるような方法を知っている方がいたら教えていただきたいです。
それと、各アイテムのclick()メソッドを呼び出した直後にselectedのgetText()を呼び出すと、まだ値が設定されていなくてテストがエラーになってしまうので、200ミリ秒waitした後、チェックを行うようにしています。