Inside appium for android


# はじめに
[
appiumを使ったWebテスト for Android OS @Windows 8.1]
(http://qiita.com/unokun/items/8d17fcb5f1cf15778ea4)の続きです。

appium for Android OSは以下の構成になっている。
* Android端末上のアプリ
* appium
* テスト プログラム

appiumは、Android端末を接続したPC側で動作する。Androidアプリとは、adb(Android SDKツール)で通信を行い、テストプログラムとはHTTPベースの通信を行う。

今回は、Androidアプリ(Google Chrome)のJUnitテストコードとログを対比させて、appiumがどのような処理を行っているか調べた。

# テスト処理
テストは、JUnit(Java)を使った。テストは以下の3つの処理から構成される。
* 初期化(setUp)
* テスト実行
* 後始末(tearDown)

## 初期化
RemoteWebDriverを作成し、ブラウザアプリ(Chrome)を起動する。

## テスト実行
　appiumのテストは、Seleniumのテストと同じであり、PC向けのテストに再利用できる。テストは、要素を取得(findElement)し、その値を評価(assert)することが主に行われる。それ以外は、ボタンクリックやキー入力がある。

ログは、--->がテストからappium、<---がその返値であり、それに囲まれている部分が一つの処理になっている。

## 後始末
ブラウザアプリChromeの終了と、RemoteWebDriverのアンロード。

# 初期化
RemoteWebDriverを作成し、ブラウザアプリChromeを起動する。
## ソース
```java
        DesiredCapabilities capabilities = new DesiredCapabilities();
        capabilities.setCapability("deviceName","Android Emulator");
        capabilities.setCapability("platformVersion", "4.4");
        capabilities.setCapability("platformName","Android");
        capabilities.setCapability("browserName", "chrome");
        driver = new RemoteWebDriver(new URL("http://127.0.0.1:4723/wd/hub"),
                capabilities);
```

## ログ
```
> info: --> POST /wd/hub/session {"desiredCapabilities":{"platformVersion":"4.4","deviceName":"Android Emulator","platformName":"Android","browserName":"chrome"}}
> info: Retrieving device
> debug: Request received with params: {"desiredCapabilities":{"platformVersion":"4.4","deviceName":"Android Emulator","platformName":"Android","browserName":"chrome"}}
> debug: Looks like we want chrome on android
> debug: Creating new appium session 79b158ca-ece2-4786-9def-40de564f6c6e
```

端末と接続
Android開発ツールであるadbを使って端末との接続を確認する。
android sdkは、c:¥java¥android-sdkにインストールし、PATHを通している。

```
> debug: Preparing device for session
> debug: Not checking whether app is present since we are assuming it's already on the device
> Debug: Checking whether adb is present
> debug: Using adb from c:\java\android-sdk\platform-tools\adb.exe
> debug: Trying to find a connected android device
> debug: Getting connected devices...
> debug: executing: "c:\java\android-sdk\platform-tools\adb.exe" devices
> debug: 1 device(s) connected
> info: Found device 015d18ad5d5bf606
> debug: Setting device id to 015d18ad5d5bf606
> debug: Waiting for device to be ready and to respond to shell commands (timeout = 5)
> debug: executing: "c:\java\android-sdk\platform-tools\adb.exe" -s 015d18ad5d5bf606 wait-for-device
> debug: executing: "c:\java\android-sdk\platform-tools\adb.exe" -s 015d18ad5d5bf606 shell "echo 'ready'"
> debug: Starting logcat capture
```

アプリ(unlock)インストール
アプリをインストールして画面ロックを解除する。
```
> debug: Pushing unlock helper app to device...
> debug: executing: "c:\java\android-sdk\platform-tools\adb.exe" -s 015d18ad5d5bf606 install "C:\java\AppiumForWindows\node_modules\appium\build\unlock_apk\unlock_apk-debug.apk"
> debug: executing: "c:\java\android-sdk\platform-tools\adb.exe" -s 015d18ad5d5bf606 shell "dumpsys window"
> debug: Writing dumpsys output to C:\java\AppiumForWindows\node_modules\appium\.dumpsys.log
> debug: Screen already unlocked, continuing.
```

Chromeを開始する
セッションを開始する。

```
> debug: Creating Chrome session
```

chrome driver 開始
```
> Debug: Ensuring Chromedriver exists
> debug: Killing any old chromedrivers, running: FOR /F "usebackq tokens=5" %a in (`netstat -nao ^| findstr /R /C:"9515 "`) do (FOR /F "usebackq" %b in (`TASKLIST /FI "PID eq %a" ^| findstr /I chromedriver.exe`) do (IF NOT %b=="" TASKKILL /F /PID %b))
> debug: No old chromedrivers seemed to exist
> debug: Spawning chromedriver with: C:\java\AppiumForWindows\node_modules\appium\build\chromedriver\windows\chromedriver.exe
> debug: [CHROMEDRIVER] Starting ChromeDriver (v2.9.248315) on port 9515
> debug: Making http request with opts: {"url":"http://127.0.0.1:9515/wd/hub/session","method":"POST","json":{"sessionId":null,"desiredCapabilities":{"chromeOptions":{"androidPackage":"com.android.chrome","androidDeviceSerial":"015d18ad5d5bf606"}}}}
> debug: Successfully started chrome session
> info: <-- POST /wd/hub/session 303 9234.938 ms - 9
> debug: Overriding session id with "010ba8a78c7c38b69b3e8d8f36076948"
> debug: Device launched! Ready for commands
> debug: Setting command timeout to the default of 60 secs
```

セッション開始
```
> debug: Appium session started with sessionId 010ba8a78c7c38b69b3e8d8f36076948
> info: --> GET /wd/hub/session/010ba8a78c7c38b69b3e8d8f36076948 {}
> debug: Appium request initiated at /wd/hub/session/010ba8a78c7c38b69b3e8d8f36076948
> debug: Request received with params: {}
> debug: Proxying command to 127.0.0.1:9515
> debug: Making http request with opts: {"url":"http://127.0.0.1:9515/wd/hub/session/010ba8a78c7c38b69b3e8d8f36076948","method":"GET"}
> debug: Proxied response received with status 200: "{\"sessionId\":\"010ba8a78c7c38b69b3e8d8f36076948\",\"status\":0,\"value\":{\"acceptSslCerts\":true,\"applicationCacheEnabled\":false,\"browserConnectionEnabled\":false,\"browserName\":\"chrome\",\"chrome\":{},\"cssSelectorsEnabled\":true,\"databaseEnabled\":false,\"handlesAlerts\":true,\"javascriptEnabled\":true,\"locationContextEnabled\":true,\"nativeEvents\":true,\"platform\":\"ANDROID\",\"rotatable\":false,\"takesHeapSnapshot\":true,\"takesScreenshot\":true,\"version\":\"36.0.1985.135\",\"webStorageEnabled\":true}}"
> info: <-- GET /wd/hub/session/010ba8a78c7c38b69b3e8d8f36076948 200 3.434 ms - 476
```

# テスト実行
## 処理(get)
URLにアクセスする。

### ソース
```java
        driver.get("http://saucelabs.com/test/guinea-pig");
```

### ログ
```
> info: --> POST /wd/hub/session/010ba8a78c7c38b69b3e8d8f36076948/url {"url":"http://saucelabs.com/test/guinea-pig"}
> debug: Appium request initiated at /wd/hub/session/010ba8a78c7c38b69b3e8d8f36076948/url
> debug: Request received with params: {"url":"http://saucelabs.com/test/guinea-pig"}
> debug: Proxying command to 127.0.0.1:9515
> debug: Making http request with opts: {"url":"http://127.0.0.1:9515/wd/hub/session/010ba8a78c7c38b69b3e8d8f36076948/url","method":"POST","json":{"url":"http://saucelabs.com/test/guinea-pig"}}
> debug: Proxied response received with status 200: {"sessionId":"010ba8a78c7c38b69b3e8d8f36076948","status":0,"value":null}
> info: <-- POST /wd/hub/session/010ba8a78c7c38b69b3e8d8f36076948/url 200 2272.921 ms - 72
```

## 処理(findElement)
HTML要素を検索する。Id、クラス名、XPathを使って検索することができる。処理(例の場合はelement)をURLに含め、それ以外をレクエストパラメータで渡している。

### ソース
```java
        WebElement idElement = driver.findElement(By.id("i_am_an_id"));
```

### ログ
```
> info: --> POST /wd/hub/session/010ba8a78c7c38b69b3e8d8f36076948/element {"using":"id","value":"i_am_an_id"}
> debug: Appium request initiated at /wd/hub/session/010ba8a78c7c38b69b3e8d8f36076948/element
> debug: Request received with params: {"using":"id","value":"i_am_an_id"}
> debug: Proxying command to 127.0.0.1:9515
> debug: Making http request with opts: {"url":"http://127.0.0.1:9515/wd/hub/session/010ba8a78c7c38b69b3e8d8f36076948/element","method":"POST","json":{"using":"id","value":"i_am_an_id"}}
> debug: Proxied response received with status 200: {"sessionId":"010ba8a78c7c38b69b3e8d8f36076948","status":0,"value":{"ELEMENT":"0.8759402201976627-1"}}
> info: <-- POST /wd/hub/session/010ba8a78c7c38b69b3e8d8f36076948/element 200 172.913 ms - 102
```

## 処理(getText)
　テキスト要素の値を取得する。この処理のみ、GETにしているのはパラメータが不要だからかな？

### ソース
```java
        assertEquals("I am a div", idElement.getText());
```

### ログ
```
> info: --> GET /wd/hub/session/010ba8a78c7c38b69b3e8d8f36076948/element/0.8759402201976627-1/text {}
> debug: Appium request initiated at /wd/hub/session/010ba8a78c7c38b69b3e8d8f36076948/element/0.8759402201976627-1/text
> debug: Request received with params: {}
> debug: Proxying command to 127.0.0.1:9515
> debug: Making http request with opts: {"url":"http://127.0.0.1:9515/wd/hub/session/010ba8a78c7c38b69b3e8d8f36076948/element/0.8759402201976627-1/text","method":"GET"}
> debug: Proxied response received with status 200: "{\"sessionId\":\"010ba8a78c7c38b69b3e8d8f36076948\",\"status\":0,\"value\":\"I am a div\"}"
> info: <-- GET /wd/hub/session/010ba8a78c7c38b69b3e8d8f36076948/element/0.8759402201976627-1/text 200 185.126 ms - 80
```


## 処理(sendKeys)
キー入力する。

### ソース
```java
        commentElement.sendKeys("This is an awesome comment");
```

###  ログ
```
> info: --> POST /wd/hub/session/010ba8a78c7c38b69b3e8d8f36076948/element/0.8759402201976627-2/value {"id":"0.8759402201976627-2","value":["This is an awesome comment"]}
> debug: Appium request initiated at /wd/hub/session/010ba8a78c7c38b69b3e8d8f36076948/element/0.8759402201976627-2/value
> debug: Request received with params: {"id":"0.8759402201976627-2","value":["This is an awesome comment"]}
> debug: Proxying command to 127.0.0.1:9515
> debug: Making http request with opts: {"url":"http://127.0.0.1:9515/wd/hub/session/010ba8a78c7c38b69b3e8d8f36076948/element/0.8759402201976627-2/value","method":"POST","json":{"id":"0.8759402201976627-2","value":["This is an awesome comment"]}}
> debug: Proxied response received with status 200: {"sessionId":"010ba8a78c7c38b69b3e8d8f36076948","status":0,"value":null}
> info: <-- POST /wd/hub/session/010ba8a78c7c38b69b3e8d8f36076948/element/0.8759402201976627-2/value 200 1222.844 ms - 72

## 処理(click)
タップイベント。

### ソース
```java
         submitElement.click();
```

### ログ
```
> debug: Appium request initiated at /wd/hub/session/010ba8a78c7c38b69b3e8d8f36076948/element/0.8759402201976627-3/click
> debug: Request received with params: {"id":"0.8759402201976627-3"}
> debug: Proxying command to 127.0.0.1:9515
> debug: Making http request with opts: {"url":"http://127.0.0.1:9515/wd/hub/session/010ba8a78c7c38b69b3e8d8f36076948/element/0.8759402201976627-3/click","method":"POST","json":{"id":"0.8759402201976627-3"}}
> debug: Proxied response received with status 200: {"sessionId":"010ba8a78c7c38b69b3e8d8f36076948","status":0,"value":null}
> info: <-- POST /wd/hub/session/010ba8a78c7c38b69b3e8d8f36076948/element/0.8759402201976627-3/click 200 944.911 ms - 72
```

# 後始末
ブラウザアプリChromeの終了と、RemoteWebDriverのアンロード。

## ソース
```java
        driver.quit();
```

## ログ
```
> debug: Appium request initiated at /wd/hub/session/010ba8a78c7c38b69b3e8d8f36076948/url
> debug: Request received with params: {}
> debug: Proxying command to 127.0.0.1:9515
> debug: Making http request with opts: {"url":"http://127.0.0.1:9515/wd/hub/session/010ba8a78c7c38b69b3e8d8f36076948/url","method":"GET"}
> debug: Proxied response received with status 200: "{\"sessionId\":\"010ba8a78c7c38b69b3e8d8f36076948\",\"status\":0,\"value\":\"https://saucelabs.com/test/guinea-pig\"}"
> info: <-- GET /wd/hub/session/010ba8a78c7c38b69b3e8d8f36076948/url 200 18.292 ms - 107

> info: --> DELETE /wd/hub/session/010ba8a78c7c38b69b3e8d8f36076948 {}
> debug: Appium request initiated at /wd/hub/session/010ba8a78c7c38b69b3e8d8f36076948
> debug: Request received with params: {}
> debug: Killing chromedriver
> debug: Chromedriver exited with code null
> debug: (killed by signal SIGTERM)
> debug: executing: "c:\java\android-sdk\platform-tools\adb.exe" -s 015d18ad5d5bf606 shell "am force-stop com.android.chrome"
> debug: Cleaning up appium session
> info: <-- DELETE /wd/hub/session/010ba8a78c7c38b69b3e8d8f36076948 200 1043.751 ms - 72 {"status":0,"value":null,"sessionId":"010ba8a78c7c38b69b3e8d8f36076948"}

> debug: Responding to client with success: {"status":0,"value":null,"sessionId":"010ba8a78c7c38b69b3e8d8f36076948"}
```

# おわりに
　Appiumがどのような処理を行っているのか、少し理解を深めることができた。