はじめに
appiumを使ったWebテスト for Android OS @Windows 8.1の続きです。
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を起動する。
ソース
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にアクセスする。
ソース
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に含め、それ以外をレクエストパラメータで渡している。
ソース
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にしているのはパラメータが不要だからかな?
ソース
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)
キー入力する。
ソース
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のアンロード。
ソース
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がどのような処理を行っているのか、少し理解を深めることができた。