Googleのスマホアプリ自動テストツールNativeDriver事始め&ハマったところ

Google公式の?スマホアプリ自動テストツールNativeDriverを試した記録とハマったところをまとめます。
ちなみにiPhoneアプリでも使えるようですが、今回はAndroidアプリで試しました。

NativeDriver公式サイト

自動テストツールって何してくれるの?と思ったら以下の30秒くらいの動画を見ると理解が早いです。

要するにユーザの入力作業をテストコードで記述して、実行するツールです。
私は何も思わなかったけど、テストツールとか知らない人にとってはアプリが勝手に操作されてて魔法みたい?
ちょっとしたサプライズにも応用できるような気がしましたが、それはまた別の機会にでも。

参考サイト
Getting Started最初のインストール方法とデモアプリの実行方法
自分のプロジェクトへの導入方法

必要なもの

まずは準備、
1.NativeDriverを取ってくる!
SVNでNativeDriverをとってきます。途中自分のGoogleのe-mailアドレスと認証を確認されます。

$ svn checkout https://nativedriver.googlecode.com/svn/trunk nativedriver --username {Google account e-mail address}

成功すると、nativedriverフォルダができます。

2. antでビルドしましょう

$ cd nativedriver/android
$ ant

3. テスト用のJUnitプロジェクトを作成
作成したJUnitプロジェクトにはnativedriver/android/buildの下にある、client-standalone.jarを外部アーカイブとして追加します。

4. 自分のアプリプロジェクトに外部アーカイブとして、server-standalone.jarを追加
先程と同様にnativedriver/android/buildの下にある、server-standalone.jarを外部アーカイブとして追加します。

5. NativeDriverが自分のアプリを操作できるように許可
自分のアプリプロジェクトのManifestファイルに以下のコードを追記。"{app_package_name}"には自分のアプリのパッケージ名を入れてください。

  <instrumentation android:targetPackage="{app_package_name}"
   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" />

6. アプリをデバイスエミュレーターでもOK)にインストール

7. テストコードがアプリを制御できるようにadbコマンドを実行
蛇足かもしれませんが、adbコマンドはandroid-sdkのplatform-tools配下にあります。(androidのバージョンによってはtoolsの配下です)
"{app_package_name}"には自分のアプリのパッケージ名を入れてください。
2行目はポートフォワードするためのコマンドです。

adb shell am instrument {app_package_name}/com.google.android.testing.nativedriver.server.ServerInstrumentation
adb forward tcp:54129 tcp:54129

8. テストプロジェクトのテストコードをJUnitとして実行!
途中Eclipse JUnit Launcherをランチャーとして選択します。
そうすると、テストコードに従って、操作が自動的に実行され、JUnitにも結果が表示されます。

テストしようとしたアプリは以下のアプリです。

自分の好きな2ケタの数字をあらかじめ考えてもらい。
画面に3で割った時のあまり、5で割った時のあまり、7で割った時のあまりを入力すると、考えていた数字を当ててくれます。
あまりを入力すると、頭の中にある数字を算出してくれるというマジック?です。余談ですが3桁の数字のバージョンも作りました。
テストとしては、56という数字を当てることを想定すると、
画面のように3で割ったあまりに2を入力、
5で割ったあまりに1を入力
7で割ったあまりに0を入力して、結果の画面に56という数字が表示されればテスト成功になります。

ハマったところは文字入力した後の遷移です。
一回一回テキストボックスをクリックして、戻るボタンを押すようにソースコードを書く必要があります。
まぁ、実際のユーザの操作もテキストボックスをタップするので、忠実といえば忠実ですね。

最後にソースコードは以下の通りです。

package com.momomemo.android.mathmagic;

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.common.AndroidKeys;

public class MathMagicTest extends TestCase {
	private AndroidNativeDriver driver;	

	protected void setUp() throws Exception {
		driver = getDriver();
	}

	protected AndroidNativeDriver getDriver() {
		return new AndroidNativeDriverBuilder()
			.withDefaultServer()
			.build();
	}

	protected void tearDown() throws Exception {
		driver.quit();
	}
	
	private void startFirstMenuActivity() {
	    driver.startActivity("com.momomemo.android.mathmagic.MathMagicActivity");
	}
	
	public void testShowMenu(){
		//戻るコマンドを入力するための準備
		String toback = "";
		toback += AndroidKeys.BACK;
		
		//Activityを開始
		startFirstMenuActivity();
		//最初のメニューのボタンを押す
		driver.findElement(By.id("button_show_menu")).click();
		
		//2ケタの数あてゲームを選択
		driver.findElement(By.id("button_number_guess1")).click();
		
		//説明を読んで次へ
		driver.findElement(By.id("button_next")).click();
		
		//ここからは答えが56になることを想定したテスト
		//3で割ったときのあまりを入力
		driver.findElement(By.id("mod3Text")).click();
		driver.findElement(By.id("mod3Text")).sendKeys("2");
		driver.findElement(By.id("mod3Text")).sendKeys(toback);
		
		//5で割ったときのあまりを入力
		driver.findElement(By.id("mod5Text")).click();
		driver.findElement(By.id("mod5Text")).sendKeys("1");
		driver.findElement(By.id("mod5Text")).sendKeys(toback);
		
		//7で割った時のあまりを入力
		driver.findElement(By.id("mod7Text")).click();
		driver.findElement(By.id("mod7Text")).sendKeys("0");
		driver.findElement(By.id("mod7Text")).sendKeys(toback);
		
		//結果を表示するボタンを押す
		driver.findElement(By.id("calculatebutton")).click();
		
		//次の画面の表示結果に56と表示されていればOK
		assertEquals("56", driver.findElement(By.id("answerView")).getText());
		
	}

}