SeleniumGrid + RobotFramework + SeleniumLibraryで、VMのWindowsのInternet Explorerを使ってテストする

今まで、

など、Mac上で動作するものに対してテストコードを書いてきました。

 
そんな中、VMWindowsInternet Explorerを使ってテストする機会がありました。

そこで、

を行うよう、SeleniumGrid + RobotFramework + SeleniumLibraryを使ってテストしてみたため、その時のメモを残します。

なお、Selenium Gridについては以下が詳しいです。
» Selenium Gridで複数の実機ブラウザで自動テスト TECHSCORE BLOG

 
目次

 

環境

今回は

という構成にしました。

なお、Selenium Grid自体は、HubとNodeを一つの端末にしても動作します。ターミナルが3つ必要になるくらいです。(Hub用、Node用、テスト実行用)

 

Mac

 

Windows

 

Mac側のSelenium Gridの環境構築

Selenium Grid用のjarファイルのダウンロード

後日AppiumでもSelenium Grid環境を構築するため、Seleniumは3.3.1を使います (現時点の最新は3.5.3)。

PythonライブラリのバージョンとSelenium Gridのバージョンが異なる場合エラーが起きることがあるため、同じバージョンのものをダウンロードします。

今回は過去のバージョンのため、ダウンロードページのprevious releasesより selenium-server-standalone-3.3.1.jar をダウンロードします。

ダウンロードしたzipを展開し、出てきたjarファイルをテスト用ディレクトリに置きます。

 

Selenium Grid Host用の設定ファイルを作成

コマンドラインに設定内容を記述してもよいのですが、今回は設定ファイルを使います。

今回使用するMacにはVM用のネットワークアダプタなど、IPが振られているネットワークアダプタが複数あります。何も設定しないと、LANのネットワークアダプタが使われないことがあります。その場合、Selenium Grid NodeからHubへ接続できず動作しません。

そのため、今回の設定ファイルには、HubのIPアドレスを記載します。

hub_config.json

{
  "host": "192.168.10.103"
}

 

Selenium Grid Hubの起動

Macのターミナルを開き、jarファイルのあるディレクトリで以下を実行します。

$ java -jar selenium-server-standalone-3.3.1.jar -role hub -hubConfig hub_config.json 

21:54:58.285 INFO - Selenium build info: version: '3.3.1', revision: '5234b32'
...
21:54:59.918 INFO - Nodes should register to http://192.168.10.103:4444/grid/register/
21:54:59.918 INFO - Selenium Grid hub is up and running

Hubが起動しました。

http://192.168.10.103:4444/grid/console へアクセスすると、以下のようになりました。

f:id:thinkAmi:20170917215832p:plain

 

VMwareのゲストOSのIP設定をブリッジへと変更

もし、VMwareの設定画面にネットワークアダプタがない場合は、新規に追加します。

その上で、ネットワークアダプタの設定を Macを共有 から ブリッジされたネットワーキング > 自動検出 へと変更します。

これでMacとゲストOSのWindowsIPアドレスが別となりました *1

 

VMのWindows10側のSelenium Gridの環境構築

jarとIEDriverServerのダウンロードと配置

NodeとなるWindowsにも、Hubと同じバージョンのjarファイルおよびIEDriverServerを任意のディレクトリに用意します。

今回用意したものは

  • selenium-server-standalone-3.3.1.jar
    • Hubと同じバージョンのもの
  • IEDriverServer.exe
    • IEDriverServer_Win32_3.3.0.zipを展開したもの
    • Windows10のOSは64bitだが、Downloadsページに32bit IEが推奨されていたため、32bit版のものを使った
    • Internet Explorer 用 WebDriver (Windows)

を同じディレクトリに入れます。

なお、jarと同じディレクトリに置けば、IEDriverServer.exeには特にPATHを通さなくても動作しました。

 

Selenium Grid Node用の設定ファイルを作成

Internet Explorerを動作させるための設定ファイルを記載します。

なお、Selenium3からは configuration というキーを付けるとエラーとなります。
Selenium 3.0.1 Chrome Node configuration - Stack Overflow

また、設定ファイルのデフォルト値は以下に記載されています。 https://github.com/SeleniumHQ/selenium/blob/master/java/server/src/org/openqa/grid/common/defaults/DefaultNodeWebDriver.json

今回はその差分を記載します。

node.json

{
  "capabilities": [
    {
      "browserName": "internet explorer",
      "platform": "WINDOWS",
      "maxInstances": 1,
      "cleanSession": true ,
      "version": "11",
      "browser-version": "11",
      "seleniumProtocol": "WebDriver"
    }
  ],
  "hub": "http://192.168.10.103:4444/grid/register",
  "host": "192.168.10.107",
  "port": 5054,
  "register": true
}

 

Internet Explorerの設定を変更

SeleniumInternet Explorerを使う場合、いくつかの設定が必要になります。

今回は以下のWikiにあるRequired Configurationに従い、設定を行います。
Required Configuration - InternetExplorerDriver · SeleniumHQ/selenium Wiki

設定内容は

  • インターネットオプションのセキュリティタブにある、 保護モードを有効にする にチェックを入れる
  • インターネットオプションの詳細体部にある 拡張保護モードを有効にするチェックを外す
  • IEを起動し、ズームを100%にする
  • Windows10の場合、IEのバージョンは11なので、レジストリに以下を追加する
    • キー:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BFCACHE
    • 値: 種類 DWORD(32ビット値) 、名前 iexplore .exe 、 データ 0
    • 今回は32bitのIEを使ったが、64bitの場合は別のなのでWikiを参照のこと

です。

 

Selenium Grid Nodeの起動

コマンドプロンプトから起動します。

>java -jar selenium-server-standalone-3.3.1.jar -role node -nodeConfig node.json
22:00:16.200 INFO - Selenium build info: version: '3.3.1', revision: '5234b32'
22:00:17.466 INFO - Registering the node to the hub: http://192.168.10.103:4444/grid/register
22:00:17.497 INFO - The node is registered to the hub and ready to use

Nodeが起動し、Hubに登録されました。

 
この結果、Macのコンソールには

21:59:07.276 INFO - Registered a node http://192.168.10.107:5054
22:00:13.005 INFO - I/O exception (java.net.SocketException) caught when processing request to {}->http://192.168.10.107:5054: Connection reset
22:00:13.006 INFO - Retrying request to {}->http://192.168.10.107:5054
22:00:17.512 INFO - Registered a node http://192.168.10.107:5054
22:00:17.512 WARN - Cleaning up stale test sessions on the unregistered node http://192.168.10.107:5054

と表示されます。

また、Selenium Grid HubのConsoleをブラウザで開くと

f:id:thinkAmi:20170917221316p:plain

に変わりました。

 

Robot Frameworkのテストコードを作成

今回もGooglePythonを検索するテストコードになります。

以前と異なる点は

  • Create Webdriverキーワードで、ブラウザ名を Remote にする
  • command_executor に、Selenium GridのHubの待ち受けURLを指定
  • desired_capabilities に、Selenium GridでIEを動かすためのDesiredCapabilitiesを指定

となります。

なお、Remoteに対するDesiredCapabilitiesの書き方は以下が参考になりました。 robotframework - Opening Chrome browser in Android device using Robot Framework script and chromedriver? - Stack Overflow

 
internet_explorer.robot

*** Settings ***

# Libraryは大文字小文字の区別があるようで、libraryとしてしまうとIDEが認識しない
Library  SeleniumLibrary


*** Keywords ***
GoogleでPythonを検索してスクリーンショットを撮り、結果を出力する
    ${caps} =  create dictionary  browserName=internet explorer  platform=WINDOWS
    create webdriver  Remote  command_executor=http://192.168.10.103:4444/wd/hub  desired_capabilities=${caps}

    # Googleのトップ画面を開く
    go to  https://www.google.co.jp/

    # タイトルにGoogleが含まれていることを確認する
    ${page_title} =  get title
    should contain  ${page_title}  Google

    # 検索後を入力して送信する
    input text  name=q  Python
    # Robot FrameworkではEnterキーは\\13になる
    # https://github.com/robotframework/Selenium2Library/issues/4っz1
    press key  name=q  \\13

    # Ajax遷移のため、適当に2秒待つ
    sleep  2sec

    # タイトルにPythonが含まれていることを確認する
    ${result_title} =  get title
    should contain  ${result_title}  Python

    # スクリーンショットを撮る
    capture page screenshot  filename=result_google_python.png

    # ログを見やすくするために改行を入れる
    log to console  ${SPACE}

    # 検索結果を表示する
    @{web_elements} =  get webelements  css=h3 > a
    :for  ${web_element}  in  @{web_elements}
    \  ${text} =  get text  ${web_element}
    \  log to console  ${text}
    \  ${href} =  call method  ${web_element}  get_attribute  href
    \  log to console  ${href}

    # ブラウザを終了する
    close browser


*** TestCases ***

GoogleでPythonを検索するテスト
    GoogleでPythonを検索してスクリーンショットを撮り、結果を出力する

 

テストの実行

準備が整ったため、Macのターミナルよりテストを実行します。

$ robot internet_explorer.robot

を実行すると、VMWindowsでIE11が起動し、GooglePythonを検索します。

テストが進むにつれMacのターミナルに

==============================
Internet Explorer                                                             
==============================
GoogleでPythonを検索するテスト                                         
Python - ウィキペディア
https://ja.wikipedia.org/wiki/Python
Pythonとは - python.jp
https://www.python.jp/about/
Python チュートリアル — Python 3.6.1 ドキュメント
https://docs.python.jp/3/tutorial/index.html
【入門者必見】Pythonとは?言語の特徴やシェア、仕事市場を徹底解説 | 侍 ...
http://www.sejuku.net/blog/7720
Pythonとは?何に使えるの?Pythonの特徴や使い道を…|Udemy メディア
https://udemy.benesse.co.jp/development/python.html
Pythonに関する12300件の投稿 - Qiita
https://qiita.com/tags/Python
Python基礎講座(1 Pythonとは) - Qiita
http://qiita.com/Usek/items/ff4d87745dfc5d9b85a4
初心者でもほぼ無料でPythonを勉強できるコンテンツ10選 - paiza開発日誌
http://paiza.hatenablog.com/entry/2015/04/09/%E5%88%9D%E5%BF%83%E8%80%85%E3%81%A7%E3%82%82%E3%81%BB%E3%81%BC%E7%84%A1%E6%96%99%E3%81%A7Python%E3%82%92%E5%8B%89%E5%BC%B7%E3%81%A7%E3%81%8D%E3%82%8B%E3%82%B3%E3%83%B3%E3%83%86%E3%83%B3%E3%83%8410
Python入門
http://www.tohoho-web.com/python/
Pythonとは - はてなキーワード - はてなダイアリー
http://d.hatena.ne.jp/keyword/Python
GoogleでPythonを検索するテスト    | PASS |

と表示されていきます。

ターミナルにPASSが表示されたところで、VMWindowsのIE11が閉じます。

また、実行ディレクトリに、IEの画面のスクリーンショットも保存されています。

f:id:thinkAmi:20170917222158p:plain

*画像は一部を切り抜いています。

 
以上より、

ができました。

 

参考

ソースコード

GitHubに上げました。 selenium_grid_sample/internet_explorer.robot ファイルが今回のテストファイルです。
thinkAmi-sandbox/RobotFramework-sample: Robot Framewrok samples

なお、 hub_config.jsonnode.json も含めています。もし使う場合は、 node.jsonSelenium Grid Nodeに渡し、IPアドレスなどを変更すると良いです。

また、 selenium-server-standalone-3.3.1.jarIEDriverServer.exe は含めていないため、それらはダウンロードしてください。

*1:Macと共有してもSelenium Grid環境を構築できるかもしれませんが、未検証です

RobotFramework + SeleniumLibrary + Appiumで、iOSシミュレータ上のSafariブラウザでテストする

以前、AndroidChromeを使うテストをRobot Frameworkで書いてみました。
RobotFramework + SeleniumLibraryにて、Android実機上のChromeを使ってテストする - メモ的な思考的な

今回は、iOSシミュレータ上のSafariを使うテストをRobot Frameworkで書いてみます。

なお、DesiredCapabilitiesの内容についてはSeleniumWikiに情報があります。
DesiredCapabilities · SeleniumHQ/selenium Wiki · GitHub

 
目次

 

環境

  • Mac OS X 10.11.6
  • Python 3.6.2
  • RobotFramework 3.0.2
  • SeleniumLibrary 3.0.0b1
  • iOS シミュレータ 10.2
  • Node.js 8.4.0
  • Xcode 8.2.1
  • AppiumとSeleniumは、いずれかの組み合わせで動作

 
今回、iOSシミュレータのSafariを使うために、Appium経由で操作してみます。

なお、RobotFrameworkとAppiumを連携するための robotframework-appiumlibrary ライブラリは不要でした。
serhatbolsu/robotframework-appiumlibrary: AppiumLibrary is an appium testing library for RobotFramework

 

環境構築

Node.jsのインストール

Appiumを使うためにはNode.jsが必要なため、Node.jsをインストールします。

 

既存のNode.jsを削除

手元のNode.jsを確認したところ、Node.jsがあったため、アンインストールします。

$ brew uninstall node
Error: Refusing to uninstall /usr/local/Cellar/node/8.1.4
because it is required by heroku 6.12.8, which is currently installed.
You can override this and force removal with:
  brew uninstall --ignore-dependencies node

以前、Heroku Toolbeltをインストールした時のものが残っているようでした。

 
今回、Heroku ToolbeltのNode.jsは後で入れ直すことにして、アンインストールします。

$ brew uninstall heroku
Uninstalling /usr/local/Cellar/heroku/6.12.8... (5,974 files, 30.7MB)
heroku 5.6.1-0976cf3 1 is still installed.
Remove all versions with `brew uninstall --force heroku`.

 
削除しきれていないようなので、Herokuのドキュメントに従って削除します。
Heroku CLI | Heroku Dev Center

$ brew uninstall --force heroku
Uninstalling heroku... (12,942 files, 79.7MB)

# herokuに書いてあった方法で追加削除
$ rm -rf ~/.local/share/heroku ~/.config/heroku ~/Library/Caches/heroku
(特に結果は表示されない)

 
もう一度確認とまだインストールされていたため、そちらもアンインストールします。

$ node -v
v8.1.4

# アンインストール
$ brew uninstall node
Uninstalling /usr/local/Cellar/node/8.1.4... (3,782 files, 44.7MB)

# 確認
$ node -v
-bash: /usr/local/bin/node: No such file or directory

 

nodebrewのインストール

Node.jsもバージョン管理したいなと思ったところ、nodebrewがありました。

そこで、以下を参考にnodebrewをインストールします。
Homebrewからnodebrewをインストールして、Node.jsをインストールするまで - Qiita

$ brew install nodebrew
Updating Homebrew...
==> Auto-updated Homebrew!
Updated 1 tap (caskroom/cask).

==> Using the sandbox
==> Downloading https://github.com/hokaccha/nodebrew/archive/v0.9.7.tar.gz
==> Downloading from https://codeload.github.com/hokaccha/nodebrew/tar.gz/v0.9.7
######################################################################## 100.0%
==> /usr/local/Cellar/nodebrew/0.9.7/bin/nodebrew setup_dirs
==> Caveats
Add path:
  export PATH=$HOME/.nodebrew/current/bin:$PATH

To use Homebrew's directories rather than ~/.nodebrew add to your profile:
  export NODEBREW_ROOT=/usr/local/var/nodebrew

Bash completion has been installed to:
  /usr/local/etc/bash_completion.d

zsh completions have been installed to:
  /usr/local/share/zsh/site-functions
==> Summary
🍺  /usr/local/Cellar/nodebrew/0.9.7: 8 files, 38KB, built in 17 seconds

 

nodebrewのセットアップ

nodebrew setup

# セットアップ
$ nodebrew setup
Fetching nodebrew...
Installed nodebrew in $HOME/.nodebrew

========================================
Export a path to nodebrew:

export PATH=$HOME/.nodebrew/current/bin:$PATH
========================================

~/.bash_profileに追記

export PATH=$HOME/.nodebrew/current/bin:$PATH

.bash_profileを再読込

$ source ~/.bash_profile

 

nodebrewを使ったNode.jsのインストール
$ nodebrew install-binary stable
Fetching: https://nodejs.org/dist/v8.4.0/node-v8.4.0-darwin-x64.tar.gz
######################################################################## 100.0%
Installed successfully

 

使うバージョンを指定
$ nodebrew use stable
use v8.4.0

 

npm init

全部Enterで進めます

$ npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.

See `npm help json` for definitive documentation on these fields
and exactly what they do.

Use `npm install <pkg>` afterwards to install a package and
save it as a dependency in the package.json file.

Press ^C at any time to quit.
package name: (selenium_appium_sample) 
version: (1.0.0) 
description: 
entry point: (index.js) 
test command: 
git repository: 
keywords: 
author: 
license: (ISC) 
About to write to path/to/robotframework_sample/selenium_appium_sample/package.json:

{
  "name": "selenium_appium_sample",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}


Is this ok? (yes) 

 

Appiumのインストール

GitHubのREADMEに従い、Appium本体をインストールします。
GitHub - appium/appium: Automation for iOS, Android, and Windows Apps.

$ npm install -g appium

npm WARN deprecated babel-core@5.8.24: Babel 5 is no longer being maintained. Upgrade to Babel 6.
npm WARN deprecated minimatch@2.0.10: Please update to minimatch 3.0.2 or higher to avoid a RegExp DoS issue
npm WARN deprecated line-numbers@0.2.0: Copy its ~20 LOC directly into your code instead.
/Users/you/.nodebrew/node/v8.4.0/bin/appium -> /Users/you/.nodebrew/node/v8.4.0/lib/node_modules/appium/build/lib/main.js

> appium-chromedriver@2.11.2 install /Users/you/.nodebrew/node/v8.4.0/lib/node_modules/appium/node_modules/appium-chromedriver
> node install-npm.js

info Chromedriver Install Installing Chromedriver version '2.28' for platform 'mac' and architecture '64'
info Chromedriver Install Opening temp file to write chromedriver_mac64 to...
info Chromedriver Install Downloading https://chromedriver.storage.googleapis.com/2.28/chromedriver_mac64.zip...
info Chromedriver Install Writing binary content to /var/folders/h0/l5plp4zd3517r988jpm481g00000gn/T/2017815-1009-nx99nt.vp8p/chromedriver_mac64.zip...
info Chromedriver Install Extracting /var/folders/h0/l5plp4zd3517r988jpm481g00000gn/T/2017815-1009-nx99nt.vp8p/chromedriver_mac64.zip to /var/folders/h0/l5plp4zd3517r988jpm481g00000gn/T/2017815-1009-nx99nt.vp8p/chromedriver_mac64
info Chromedriver Install Creating /Users/you/.nodebrew/node/v8.4.0/lib/node_modules/appium/node_modules/appium-chromedriver/chromedriver/mac...
info Chromedriver Install Copying unzipped binary, reading from /var/folders/h0/l5plp4zd3517r988jpm481g00000gn/T/2017815-1009-nx99nt.vp8p/chromedriver_mac64/chromedriver...
info Chromedriver Install Writing to /Users/you/.nodebrew/node/v8.4.0/lib/node_modules/appium/node_modules/appium-chromedriver/chromedriver/mac/chromedriver...
info Chromedriver Install /Users/you/.nodebrew/node/v8.4.0/lib/node_modules/appium/node_modules/appium-chromedriver/chromedriver/mac/chromedriver successfully put in place

> appium-selendroid-driver@1.6.2 install /Users/you/.nodebrew/node/v8.4.0/lib/node_modules/appium/node_modules/appium-selendroid-driver
> node ./bin/install.js

dbug AndroidDriver Getting Java version
info AndroidDriver Java version is: 1.8.0_144
info Selendroid Ensuring /Users/you/.nodebrew/node/v8.4.0/lib/node_modules/appium/node_modules/appium-selendroid-driver/selendroid/download exists
info Selendroid Downloading Selendroid standalone server version 0.17.0 from http://repo1.maven.org/maven2/io/selendroid/selendroid-standalone/0.17.0/selendroid-standalone-0.17.0-with-dependencies.jar --> /Users/you/.nodebrew/node/v8.4.0/lib/node_modules/appium/node_modules/appium-selendroid-driver/selendroid/download/selendroid-server-7cf7163ac47f1c46eff95b62f78b58c1dabdec534acc6632da3784739f6e9d82.jar
info Selendroid Writing binary content to /Users/you/.nodebrew/node/v8.4.0/lib/node_modules/appium/node_modules/appium-selendroid-driver/selendroid/download/selendroid-server.jar.tmp
info Selendroid Selendroid standalone server downloaded
info Selendroid Determining AndroidManifest location
info Selendroid Determining server apk location
info Selendroid Extracting manifest and apk to /Users/you/.nodebrew/node/v8.4.0/lib/node_modules/appium/node_modules/appium-selendroid-driver/selendroid/download
info Selendroid Copying manifest and apk to /Users/you/.nodebrew/node/v8.4.0/lib/node_modules/appium/node_modules/appium-selendroid-driver/selendroid
info Selendroid Cleaning up temp files
info Selendroid Fixing AndroidManifest icon bug

> appium-uiautomator2-driver@0.3.3 install /Users/you/.nodebrew/node/v8.4.0/lib/node_modules/appium/node_modules/appium-uiautomator2-driver
> node ./bin/install.js

dbug AndroidDriver Getting Java version
info AndroidDriver Java version is: 1.8.0_144
info UiAutomator2 downloading UiAutomator2 Server APK v0.1.5 : https://github.com/appium/appium-uiautomator2-server/releases/download/v0.1.5/appium-uiautomator2-server-v0.1.5.apk
info UiAutomator2 downloading UiAutomator2 Server test APK v0.1.5 : https://github.com/appium/appium-uiautomator2-server/releases/download/v0.1.5/appium-uiautomator2-server-debug-androidTest.apk
info UiAutomator2 UiAutomator2 Server APKs downloaded

> appium-windows-driver@0.5.0 install /Users/you/.nodebrew/node/v8.4.0/lib/node_modules/appium/node_modules/appium-windows-driver
> node install-npm.js

Not installing WinAppDriver since did not detect a Windows system

> fsevents@1.1.2 install /Users/you/.nodebrew/node/v8.4.0/lib/node_modules/appium/node_modules/fsevents
> node install

[fsevents] Success: "/Users/you/.nodebrew/node/v8.4.0/lib/node_modules/appium/node_modules/fsevents/lib/binding/Release/node-v57-darwin-x64/fse.node" already installed
Pass --update-binary to reinstall or --build-from-source to recompile

> heapdump@0.3.9 install /Users/you/.nodebrew/node/v8.4.0/lib/node_modules/appium/node_modules/heapdump
> node-gyp rebuild

  CXX(target) Release/obj.target/addon/src/heapdump.o
  SOLINK_MODULE(target) Release/addon.node
+ appium@1.6.5
added 692 packages in 330.588s

 

Appium-doctorのインストール
$ npm install -g appium-doctor

/Users/you/.nodebrew/node/v8.4.0/bin/appium-doctor -> /Users/you/.nodebrew/node/v8.4.0/lib/node_modules/appium-doctor/appium-doctor.js
+ appium-doctor@1.4.3
added 155 packages in 28.769s

 

インストールされた内容を確認

[Node.js] インストール済みのパッケージ一覧を表示する - Qiita

$ npm -g list --depth=0
/Users/you/.nodebrew/node/v8.4.0/lib
├── appium@1.6.5
├── appium-doctor@1.4.3
└── npm@5.3.0

 

Javaまわりの設定を.bash_profileへ追加

Appium-doctorを実行したところ、 JAVA_HOME/bin のエラーが出ていたため、以下を参考に設定を追加します。
Appium Doctor - unable to set JAVA_HOME/bin - Issues/Bugs - Appium Discuss

export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_144.jdk/Contents/Home
export PATH=$PATH:$JAVA_HOME/bin

 

CarthageをHomebrewでインストール

Appium-doctorを実行したところ、 Carthage でエラーが出ました。

$ appium-doctor

info AppiumDoctor Appium Doctor v.1.4.3
info AppiumDoctor ### Diagnostic starting ###
info AppiumDoctor  ✔ The Node.js binary was found at: /Users/you/.nodebrew/current/bin/node
info AppiumDoctor  ✔ Node version is 8.4.0
info AppiumDoctor  ✔ Xcode is installed at: /Applications/Xcode.app/Contents/Developer
info AppiumDoctor  ✔ Xcode Command Line Tools are installed.
info AppiumDoctor  ✔ DevToolsSecurity is enabled.
info AppiumDoctor  ✔ The Authorization DB is set up properly.
WARN AppiumDoctor  ✖ Carthage was NOT found!
info AppiumDoctor  ✔ HOME is set to: /Users/you
info AppiumDoctor  ✔ ANDROID_HOME is set to: /Users/you/android/
info AppiumDoctor  ✔ JAVA_HOME is set to: /Library/Java/JavaVirtualMachines/jdk1.8.0_144.jdk/Contents/Home
info AppiumDoctor  ✔ adb exists at: /Users/you/android/platform-tools/adb
info AppiumDoctor  ✔ android exists at: /Users/you/android/tools/android
info AppiumDoctor  ✔ emulator exists at: /Users/you/android/tools/emulator
info AppiumDoctor  ✔ Bin directory of $JAVA_HOME is set
info AppiumDoctor ### Diagnostic completed, one fix needed. ###
info AppiumDoctor 
info AppiumDoctor ### Manual Fixes Needed ###
info AppiumDoctor The configuration cannot be automatically fixed, please do the following first:
WARN AppiumDoctor - Please install Carthage. Visit https://github.com/Carthage/Carthage#installing-carthage for more information.
info AppiumDoctor ###
info AppiumDoctor 
info AppiumDoctor Bye! Run appium-doctor again when all manual fixes have been applied!
info AppiumDoctor 

 
Carthageの最新版は、Xcode 8.3系が必要です。

ただ、都合により手元のMacSierraにはできないため、以下を参考に古いバージョンのCarthageをインストールします。
Homebrewで過去のバージョンを使いたい - Carpe Diem

Carthage 0.23.0であれば、Xcode 8.2.1でも動作するようでした。

# ログを確認
$ brew log carthage --oneline
Warning: homebrew/core is a shallow clone so only partial output will be shown.
To get a full clone run:
  git -C "$(brew --repo homebrew/core)" fetch --unshallow
75d2a4a carthage: update 0.25.0 bottle.
4253a70 carthage 0.25.0
4a9efba carthage: update 0.24.0 bottle.
f74d9ba carthage 0.24.0
330abb7 carthage: update 0.23.0 bottle.
9e8ceb0 carthage 0.23.0
6ae4f69 carthage: update 0.22.0 bottle.
80e29a8 carthage 0.22.0
632ebc1 carthage: update 0.21.0 bottle.
2cad486 carthage 0.21.0
6d42f60 carthage: update 0.20.1 bottle.
a98dcba carthage 0.20.1
d3e71df carthage: update 0.20.0 bottle.
2a81ba5 carthage 0.20
3e8dea9 carthage: update 0.19.1 bottle.
75270e7 carthage 0.19.1
016acde gosu: update 1.14.2 bottle.

# HomebrewのFormulaディレクトリへ移動
$ cd /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core/Formula/

# git fetch
$ git fetch --unshallow
remote: Counting objects: 290412, done.
remote: Compressing objects: 100% (128802/128802), done.
remote: Total 290412 (delta 162162), reused 287051 (delta 158817), pack-reused 0
Receiving objects: 100% (290412/290412), 69.61 MiB | 392.00 KiB/s, done.
Resolving deltas: 100% (162162/162162), completed with 3292 local objects.

# ログを再確認
$ brew log carthage --oneline | grep 0.23.0
330abb7 carthage: update 0.23.0 bottle.
9e8ceb0 carthage 0.23.0

 
ハッシュがわかったため、インストールします。

# git checkoutで戻す
$ git checkout 330abb7 carthage.rb 

# brew installでインストールする
$ brew install carthage
==> Downloading https://homebrew.bintray.com/bottles/carthage-0.23.0.el_capitan.bottle.tar.gz
######################################################################## 100.0%
==> Pouring carthage-0.23.0.el_capitan.bottle.tar.gz
==> Caveats
Bash completion has been installed to:
  /usr/local/etc/bash_completion.d

zsh completions have been installed to:
  /usr/local/share/zsh/site-functions
==> Summary
🍺  /usr/local/Cellar/carthage/0.23.0: 64 files, 22.4MB

# Carthageのバージョンを確認
$ carthage --version
Please update to the latest Carthage version: 0.25.0. You currently are on 0.23.0
Unrecognized command: '--version'. See `carthage help`.

 
インストールが終わったため、Homebrewのリポジトリを戻しておきます。

$ git reset HEAD
Unstaged changes after reset:
M   Formula/carthage.rb
$ git checkout .

 
再度確認したところ、OKそうでした。

$ appium-doctor
info AppiumDoctor Appium Doctor v.1.4.3
info AppiumDoctor ### Diagnostic starting ###
info AppiumDoctor  ✔ The Node.js binary was found at: /Users/you/.nodebrew/current/bin/node
info AppiumDoctor  ✔ Node version is 8.4.0
info AppiumDoctor  ✔ Xcode is installed at: /Applications/Xcode.app/Contents/Developer
info AppiumDoctor  ✔ Xcode Command Line Tools are installed.
info AppiumDoctor  ✔ DevToolsSecurity is enabled.
info AppiumDoctor  ✔ The Authorization DB is set up properly.
info AppiumDoctor  ✔ Carthage was found at: /usr/local/bin/carthage
info AppiumDoctor  ✔ HOME is set to: /Users/you
info AppiumDoctor  ✔ ANDROID_HOME is set to: /Users/you/android/
info AppiumDoctor  ✔ JAVA_HOME is set to: /Library/Java/JavaVirtualMachines/jdk1.8.0_144.jdk/Contents/Home
info AppiumDoctor  ✔ adb exists at: /Users/you/android/platform-tools/adb
info AppiumDoctor  ✔ android exists at: /Users/you/android/tools/android
info AppiumDoctor  ✔ emulator exists at: /Users/you/android/tools/emulator
info AppiumDoctor  ✔ Bin directory of $JAVA_HOME is set
info AppiumDoctor ### Diagnostic completed, no fix needed. ###
info AppiumDoctor 
info AppiumDoctor Everything looks good, bye!
info AppiumDoctor 

 

iOS シミュレータの準備

Xcodeを起動し、 Window > Devices より、インストール済のシミュレータ一覧を表示します。

次に左下の + ボタン > Add Simulator よりシミュレータを追加します。

項目名
Simulator Name iOS10.2 for RF
Device Type iPhone 7 Plus
OS Version iOS 10.2

 

Robot Frameworkのテストコード実装

今回はGoogleでログインボタンを押してログイン画面へと遷移するテストを書いてみます。

*** Settings ***

# Libraryは大文字小文字の区別があるようで、libraryとしてしまうとIDEが認識しない
Library  SeleniumLibrary

# テストケースごとにブラウザを閉じる
Test Teardown  close browser

*** Keywords ***
Googleのトップページでスクリーンショットを撮る
    # iOSシミュレータを使うためのDesired Capabilitiesを設定する
    # platformVersionとdeviceNameはXcodeで作成した内容を指定
    ${caps}=  create dictionary  browserName=safari  platformName=iOS  platformVersion=10.2
    ...                          deviceName=iOS10.2 for RF

    # WebDriverにはRemote、command_executorにはAppiumの待ち受けているURL、
    # desired_capabilitiesには作成したDesired Capabilitiesをそれぞれ指定
    create webdriver  Remote  command_executor=http://localhost:4723/wd/hub  desired_capabilities=${caps}

    # Googleのトップページを開く
    go to  https://www.google.co.jp/

    # スクリーンショットを撮る
    capture page screenshot  filename=result_google_top.png


*** TestCases ***

Googleのトップページに関するテスト
    [Tags]  signin
    Googleのトップページでスクリーンショットを撮る

 

テスト実行

Appiumの起動

新しいターミナルを開いて、Appiumを起動します。

$ appium
[Appium] Welcome to Appium v1.6.5
[Appium] Appium REST http interface listener started on 0.0.0.0:4723

 

テストコードの実行

RobotFrameworkのテストを実行します。初回はシミュレータが起動するまでにかなり時間がかかります。

しばらく待つと、以下のようにテストをパスします。

# RobotFrameworkを実行
# iオプションでTag指定(topというタグがついているテストのみ実行)
$ robot -i top ios.robot 
===========================================
Ios
===========================================
Googleのトップページに関するテスト  | PASS |
-------------------------------------------
Ios                             | PASS |
1 critical test, 1 passed, 0 failed

 
また、iOSシミュレータの画面のスクリーンショットが撮られ、テスト実行時のディレクトリへと保存されます。

f:id:thinkAmi:20170915221906p:plain

 

Googleで検索するテスト

Selenium > 3.3.1 & Appium 1.6.5では失敗

続いて、Androidのときと同じようにGooglePythonを検索するテストを書いてみます。

GoogleでPythonを検索してスクリーンショットを撮り、結果を出力する
    ${caps}=  create dictionary  browserName=safari  platformName=iOS  platformVersion=10.2
    ...                          deviceName=iOS10.2 for RF
    create webdriver  Remote  command_executor=http://localhost:4723/wd/hub  desired_capabilities=${caps}
    go to  https://www.google.co.jp/

    # タイトルにGoogleが含まれていることを確認する
    ${page_title} =  get title
    should contain  ${page_title}  Google

    # 検索語を入力して送信する
    input text  name=q  Python
    # Robot FrameworkではEnterキーは\\13になる
    # https://github.com/robotframework/Selenium2Library/issues/4
    press key  name=q  \\13

    # Ajax遷移のため、適当に2秒待つ
    sleep  2sec

    # タイトルにPythonが含まれていることを確認する
    ${result_title} =  get title
    should contain  ${result_title}  Python

    # スクリーンショットを撮る
    capture page screenshot  filename=result_google_python.png

    # ログを見やすくするために改行を入れる
    log to console  ${SPACE}

    # 検索結果を表示する
    @{web_elements} =  get webelements  css=h3 > a
    :for  ${web_element}  in  @{web_elements}
    \  ${text} =  get text  ${web_element}
    \  log to console  ${text}
    \  ${href} =  call method  ${web_element}  get_attribute  href
    \  log to console  ${href}

 
実行します。

$ robot -i python ios.robot 
========================================
Ios
========================================
GoogleでPythonを検索するテスト  | FAIL |
WebDriverException: Message: Parameters were incorrect. We wanted {"required":["value"]} and you sent ["text","value","id","sessionId"]
----------------------------------------
Ios                          | FAIL |
1 critical test, 0 passed, 1 failed

テストが失敗しました。

エラーメッセージで検索すると、以下のIssueがありました。
Python Selenium client incompatible with Appium server 1.6.4. · Issue #8253 · appium/appium · GitHub

SendKeyまわりに不具合があるようです。

v1.6.6には取り込まれるそうなので、その時にまた確認することにします。

もしSendKeyまわりを使う場合には、SeleniumやAppiumを古いバージョンにして使う必要がありそうです。

 

Selenium == 3.3.1 & Appium 1.6.5では成功

どのバージョンなら動くかを調べたところ、以下に情報がありました。Selenium3.3.1 にすれば良さそうです。
send_keys -> Message: Parameters were incorrect. We wanted {“required”:[“value”]} and you sent [“text”,“sessionId”,“id”,“value”] · Issue #162 · appium/python-client · GitHub

 
バージョンを切り替えます。

# seleniumだけ3.3.1、あとは同じ
$ pip list
pip (9.0.1)
robotframework (3.0.2)
robotframework-seleniumlibrary (3.0.0b1)
selenium (3.3.1)
setuptools (28.8.0)

テストを実行してみます。

$ robot -i python ios.robot 
==============================================================================
Ios                                                                           
==============================================================================
GoogleでPythonを検索するテスト                                         
Python - ウィキペディア
https://ja.m.wikipedia.org/wiki/Python
【入門者必見】Pythonとは?言語の特徴やシェア、仕事市場を徹底解説 - 侍エンジニア塾
http://www.sejuku.net/blog/7720
Python基礎講座(1 Pythonとは) - Qiita
http://qiita.com/Usek/items/ff4d87745dfc5d9b85a4
Pythonとは?何に使えるの?Pythonの特徴や使い道を…|Udemy メディア
https://udemy.benesse.co.jp/development/python.html
Python入門
http://www.tohoho-web.com/python/
初心者でもほぼ無料でPythonを勉強できるコンテンツ10選 - paiza開発日誌
http://paiza.hatenablog.com/entry/2015/04/09/%E5%88%9D%E5%BF%83%E8%80%85%E3%81%A7%E3%82%82%E3%81%BB%E3%81%BC%E7%84%A1%E6%96%99%E3%81%A7Python%E3%82%92%E5%8B%89%E5%BC%B7%E3%81%A7%E3%81%8D%E3%82%8B%E3%82%B3%E3%83%B3%E3%83%86%E3%83%B3%E3%83%8410
Python チュートリアル — Python 3.6.1 ドキュメント
https://docs.python.jp/3/tutorial/index.html
Python 3.6.1 ドキュメント
https://docs.python.jp/3/index.html
GoogleでPythonを検索するテスト                                        | PASS |
------------------------------------------------------------------------------
Ios                                                                   | PASS |
1 critical test, 1 passed, 0 failed

成功しました。

スクリーンショットも問題なく撮れています。

f:id:thinkAmi:20170915221930p:plain

 

Selenium == 3.5.0 & Appium 1.7.0では成功 (2017/9/20追記)

Appium1.7.0がリリースされていたため、インストールして試してみました。

# アップデート
$ npm install -g appium
...
+ appium@1.7.0
added 78 packages, removed 110 packages and updated 92 packages in 161.01s

# バージョンを確認
$ appium --version
1.7.0

# Python環境を確認
$ pip list
robotframework (3.0.2)
robotframework-seleniumlibrary (3.0.0b1)
selenium (3.5.0)

 
環境が整いましたので、テストを実行してみます。

$ robot -i python ios.robot 

===============================
Ios
===============================
GoogleでPythonを検索するテスト                                         
Python - ウィキペディア
https://ja.m.wikipedia.org/wiki/Python
Python基礎講座(1 Pythonとは) - Qiita
http://qiita.com/Usek/items/ff4d87745dfc5d9b85a4
【入門者必見】Pythonとは?言語の特徴やシェア、仕事市場を徹底解説 ...
http://www.sejuku.net/blog/7720
Python 3を使うべきでない場合(なんてない) | プログラミング | ...
http://postd.cc/case-python-3/
初心者でもほぼ無料でPythonを勉強できるコンテンツ10選 - paiza開発 .. ...
http://paiza.hatenablog.com/entry/2015/04/09/%E5%88%9D%E5%BF%83%E8%80%85%E3%81%A7%E3%82%82%E3%81%BB%E3%81%BC%E7%84%A1%E6%96%99%E3%81%A7Python%E3%82%92%E5%8B%89%E5%BC%B7%E3%81%A7%E3%81%8D%E3%82%8B%E3%82%B3%E3%83%B3%E3%83%86%E3%83%B3%E3%83%8410
Pythonとは?何に使えるの?Pythonの特徴や使い道を… ...
https://udemy.benesse.co.jp/development/python.html
Python入門
http://www.tohoho-web.com/python/
Python 3.6.1 ドキュメント
https://docs.python.jp/3/index.html
Python チュートリアル — Python 3.6.1 ドキュメント
https://docs.python.jp/3/tutorial/index.html
GoogleでPythonを検索するテスト                                        | PASS |

テストがPASSしました。

Appium1.7.0ではsend_keysの不具合は修正されたようです。

 

Appiumの停止

そのままではAppiumは停止しないため、 Cmd + C で停止させます。

 

ソースコード

GitHubに上げました。 selenium_appium_sample/ios.robot ファイルが今回のテストファイルです。
thinkAmi-sandbox/RobotFramework-sample: Robot Framewrok samples

#pyconjp PyCon JP 2017に参加しました

9/8と9/9に、早稲田大学西早稲田キャンパス63号館で開催された「PyCon JP 2017」に参加しました。
PyCon JP 2017 in Tokyo | Sep 7th – Sep 10th

前回PyCon JPに参加したのは2012年だったようで、5年ぶりの参加でした。
PyCon JP 2012に参加してきました(9/15,16) - メモ的な思考的な

 
以下、簡単な感想を2日間まとめてメモしておきます。

目次

 

Keynote

Peter Wang氏

初日のKeynoteです。遅れて会場入りしたこともあり、既に始まっていました。

自分の知識不足もあり、データサイエンス系のところはなかなか難しかったですが、コミュニティのスタイルはその国にあった形があるというところが印象に残りました。

 

Masaaki Horikoshi氏

こちらは2日目のKeynoteです。

OSS活動は良いと分かっていてもハードルが高く感じるために、それを下げてくれるKeynoteでした。初めてOSS活動を開始する時に参考になるお話がいろいろとありました。

特に、貢献先は自分の興味があるOSSに絞ること、解決しやすいIssueから取り組みはじめると良いというのが印象に残りました。

 

参加したトーク

Pythonとパッケージングと私 (Atsushi Odagiri氏)

setup.pyとか雰囲気で書いているため、パッケージングまわりを知りたくて参加しました。

setuptoolsの30.3.0からsetup.cfgが使えるようになるとのことで、こうなればsetup.pyがスッキリして良さそうでした。

ただ、仮想環境を作った時のsetuptoolsのバージョンがまだそこまでいっていないため、実際に使えるようになるのはもう少し先というのが残念です…

 

メディア会議

技術書はどのように作られるのか気になって参加しました。

パネルディスカッション形式で、本を作る裏側が見えて良かったです。

 

Djangoフレームワークのユーザーモデルと認証 (Shinya Okano氏)

昔、Djangoの認証系をさわったことがあったので、知識を最新にアップデートするために参加しました。

class-based viewでいろいろと書けるようになったのは本当に嬉しい感じです。

 

len()関数がオブジェクトの長さを手にいれる仕組み (Takayuki Shimizukawa氏)

Pythonのコアな話はなかなか日常に登場しないので、気になって参加しました。

関数とアダプタの関係、そしてチェック機構はアダプタ側に持たせていると知り、ためになりました。

Pythonにおけるプロトコルの概念や一覧の紹介もあり、こちらも参考になりました。

 

How (and Why) We Speak in Unicode (Devon Peticolas氏)

しばらく前に 'ascii' codec can't decode byte なエラーと格闘したことがあったので、PythonUnicodeまわりを知ろうと思い参加しました。

Unicodeに至るまでの歴史の解説の中に、スライドの中にアスキーアートが登場したり、日本語の事情が含まれていたりと、なかなかおもしろかったです。

 

Secrets of a WSGI master (Graham Dumpleton氏)

WSGIまわりをさわったことがあったため、WSGIの知識を深めたくて参加しました。

PEP3333に基づいたWSGIの説明と、mod_wsgi の使い方と設定、mod_wsgi-expressの例やDockerでの利用方法がありました。

mod_wsgiをさわる機会はまだまだありそうなので、いろいろと参考になったのと、今後使う時は参照しようと思いました。

 

OpenAPIを利用したPythonWebアプリケーション開発 (Takuro Wada氏)

Swaggerという単語は聞いたことがあったので、具体的な内容を知りたくて参加しました。

Open APIと、現在のバージョン(2.0と3.0)、また各言語向けのライブラリが紹介されていて参考になりました。

 

Python におけるドメイン駆動設計(戦術面)の勘どころ (Junya Hayashi氏)

ドメイン駆動設計をどうPythonに落とし込めばよいのかよく分かっていないため、それを知りたくて参加しました。

概念から始まり、Pythonで実装する時にダメな実装方法と良い実装方法の解説がありました。

サンプルソースコードも公開されていたため、あとでコードを読みつつ理解したいと思います。

 

機械学習におけるデータの再現性について (Yuichiro Someya氏)

データの再現性についてどのように実現するのだろうと気になって参加しました。

再現性におけるつらいところが分かるとともに、 akagi というライブラリにより解決した部分の解説がありました。

それでもまだつらい部分は残るようで、この解決はまた大変そうだと感じました。

 

Pythonをとりまく並行/非同期の話 (tell-k氏)

Pythonの並行/非同期についてふわっとしか理解していないため参加しました。

用語の定義から実装例まで分かりやすい解説があり、とてもためになりました。

資料もきちんとまとまっていたのがありがたいです。今後このあたりをさわるときは、もう一度読み返そうと思います。

 

AWS APIGateway + Python Lambda + NEologdで作るサーバレス日本語形態素解析API (Satoru Kadowaki氏)

実装を例に、工夫したところや苦労したところの情報共有がありました。

NEologdの辞書を充実させる方向ではなく、前処理を頑張る方向での実装でした。前処理の頑張りにより辞書が変わっても結果は変わらなそうなのが印象に残りました。

 

ブース

トーク以外の時間は、主にブースにて過ごしました。

Python/Django + HoloLensなアプリをメインに体験していただきました。

 

その他

ごはん

今回は、2日間を通して、朝・昼・おやつ、そして1日目のパーティと、会場の外に出ることなくごはんをいただけました。

いずれもボリューム満点な上、お昼ごはんは種類の選択肢もありました。ありがたい限りです。

 

モノタロウ侍さん

モノタロウ侍さんにポーズをいただきました。

 

PyCon JP 2018について

既に開催が決まっていました。

2018/9/17(月・祝)~9/18(火)、場所は大田区産業プラザPiO(Plaza Industry Ota)とのことです。
交通アクセス|大田区産業プラザPiO

 
最後になりましたが、PyCon JP 2017を運営してくださったみなさま、ありがとうございました。

Bitbucketにて、あるブランチのファイルの最新版をURLで指定する

Bitbucketにて、あるブランチのファイルの最新版をURLで指定しようとして悩んだのでメモ。

 
通常、BitbucketのあるブランチのファイルのURLには、Gitのコミットハッシュが含まれます。

例えば、 python-bitbucket というライブラリのREADME.rstについてブラウザでリンクをクリックしていくと

のように、 src の下に、Gitのコミットハッシュが含まれます。

 
Gitのコミットハッシュを使わない方法を調べたところ、stackoverflowに情報がありました。
hyperlink - Link latest file on Bitbucket Git repository - Stack Overflow

src/[branch_name]/path/to/file を指定すれば良いとのことです。

 
そのため、python-bitbucketのブランチ release/0.10 のREADME.rstの最新版の場合には、

となります。

ブランチ名に / が含まれていても、そのままURLに書けば良いようです。

RobotFramework + SeleniumLibraryにて、Android実機上のChromeを使ってテストする

Android実機上のChromeを使うテストをRobotFrameworkで書く機会があったため、メモを残します。

なお、環境構築などは以下が参考になりました。ありがとうございました。

 
目次

 

環境

 
なお、このMacにはJDK1.8がインストール済です。必要かどうか分かりませんが、うまくいかない場合はJDKも入れてみてください。

 

準備

Android接続環境の構築

手元のMacにはAndroid接続環境がなかったため、環境を構築します。

Slideshareの資料では、Android SDK Toolsをインストールし、 adb devices を使ってAndroid実機が接続されているかを確認していました。

現時点でadb コマンドを使うには Platform-tools のインストールが必要です。
IDE および SDK ツールの更新 | Android Studio

そのため、

  • Android Studioをインストールし、Platform-toolsをGUIでインストール
  • Android SDK Toolsをダウンロードし、Platform-toolsをCUIでインストール
    • 昔はAndroid SDK ToolsのGUIでインストールできたが、最近削除された

のどちらかを行います。

 
今回は

  • Android実機にアプリをデプロイすることはない
  • Android実機上のChromeを動かすだけ
  • インストールは必要最小限にしたい

のため、Android SDK ToolsのCUIでインストールすることにしました。

 

Android SDK Toolsのダウンロード

以下のページの下部にある、「コマンドライン ツールのみ入手する」からダウンロードします。
https://developer.android.com/studio/index.html?hl=ja#downloads

今回は、 sdk-tools-darwin-3859397.zip をダウンロードしました。

ダウンロード後、任意のディレクトリに展開しました。

 

platform-toolsのインストール

以下を参考に、sdkmanager を使ってコマンドラインにてインストールします。
sdkmanager | Android Studio

# インストール可能なものを確認
$ ./bin/sdkmanager --list
...
platform-tools                    | 26.0.0       | Android SDK Platform-Tools       
...

# platform-toolsをインストール
$ ./bin/sdkmanager "platform-tools"
# 途中でAcceptが出るので、y
Accept? (y/N): y
done

 

接続確認

以下の手順に従い、端末の接続を確認します。
ハードウェア端末上でアプリを実行する | Android Studio

なお、MacにはUSB Driverは不要のようです。

$ ./platform-tools/adb devices
List of devices attached
* daemon not running. starting it now at tcp:5037 *
* daemon started successfully *
xxxxxxxx     unauthorized

 
この時点で実機を見ると「USBデバックを許可しますか?」が表示されるため、OKを押します

再度実行します。

$ ./platform-tools/adb devices
List of devices attached
xxxxxxxx     device

認識されたようです。

 

.bashprofileの設定

以下を参考に、末尾に設定を追加します。
android sdk tools 25.3.0 に関しての備忘メモ - exception think

# for Android
export ANDROID_HOME=$HOME/android/
PATH=$ANDROID_HOME/tools:$PATH
PATH=$ANDROID_HOME/tools/bin:$PATH
PATH=$ANDROID_HOME/platform-tools:$PATH

 

ChromeDriverの起動

事前にChromeDriverを起動しておくことで、Android実機上のChromeに接続できるようになります。

$ chromedriver
Starting ChromeDriver 2.31.488774 (7e15618d1bf16df8bf0ecf2914ed1964a387ba0b) on port 9515
Only local connections are allowed.

 
以上で準備が完了しました。

 

テストコードの実行

RobotFrameworkのテストコードを作成
Create Webdriverについて

以前同様、GooglePythonを検索するテストコードを作成します。

ポイントはCreate Webdriverのところです。

PythonSelenium

options = webdriver.ChromeOptions()
options.add_experimental_option('androidPackage', 'com.android.chrome')
driver = webdriver.Chrome(chrome_options=options)

となる場合、RobotFrameworkでは

${options} =  evaluate  sys.modules['selenium.webdriver'].ChromeOptions()  sys
call method  ${options}  add_experimental_option  androidPackage  com.android.chrome
create webdriver  Chrome  chrome_options=${options}

となります。

 

ソースコード全体
*** Settings ***

Library  SeleniumLibrary


*** Keywords ***
GoogleでPythonを検索してスクリーンショットを撮り、結果を出力する
    # 以下のコードをRobot Framework風にした
    # http://qiita.com/orangain/items/db4594113c04e8801aad

    # 以下を参考に、Chromeのオプションを追加して、Chromeを起動する
    # https://sites.google.com/a/chromium.org/chromedriver/getting-started/getting-started---android
    ${options} =  evaluate  sys.modules['selenium.webdriver'].ChromeOptions()  sys
    call method  ${options}  add_experimental_option  androidPackage  com.android.chrome
    create webdriver  Chrome  chrome_options=${options}

    # Googleのトップ画面を開く
    go to  https://www.google.co.jp/

    # タイトルにGoogleが含まれていることを確認する
    ${page_title} =  get title
    should contain  ${page_title}  Google

    # 検索後を入力してEnter
    input text  name=q  Python
    # Robot FrameworkではEnterキーは\\13になる
    # https://github.com/robotframework/Selenium2Library/issues/4
    press key  name=q  \\13

    # Ajax遷移のため、適当に2秒待つ
    sleep  2sec

    # タイトルにPythonが含まれていることを確認する
    ${result_title} =  get title
    should contain  ${result_title}  Python

    # スクリーンショットを撮る
    capture page screenshot  filename=result_google_python.png

    # ログを見やすくするために改行を入れる
    log to console  ${SPACE}

    # 検索結果を表示する
    @{web_elements} =  get webelements  css=h3 > a
    :for  ${web_element}  in  @{web_elements}
    \  ${text} =  get text  ${web_element}
    \  log to console  ${text}
    \  ${href} =  call method  ${web_element}  get_attribute  href
    \  log to console  ${href}

    # ブラウザを終了する
    close browser


*** TestCases ***

GoogleでPythonを検索するテスト
    GoogleでPythonを検索してスクリーンショットを撮り、結果を出力する

 

テストの実行

Android実機上でChromeが起動し、テストコードが実行されました。

$ robot google.robot 
================================
Google
================================
GoogleでPythonを検索するテスト
Python - ウィキペディア
https://ja.wikipedia.org/wiki/Python
...
GoogleでPythonを検索するテスト    | PASS |

 
スクリーンショットAndroid上のChromeの画面が撮れていました。

f:id:thinkAmi:20170901220911p:plain

 

ソースコード

GitHubに上げました。 selenium_android_sample/android_chrome.robot ファイルが今回のテストファイルです。
thinkAmi-sandbox/RobotFramework-sample: Robot Framewrok samples

RobotFrameworkのSelenium2Libraryの名前が、SeleniumLibraryへと変更されてた

RobotFrameworkのSelenium2LibraryのGitHubを見ていたところ、名前が変更されたのに気づいたため、メモ。

 
目次

 

環境

  • Mac OS X 10.11.6
  • Python 3.6.2
  • Google Chrome 60.0.3112.113 (stable)
  • ChromeDriver 2.31 (stable)
  • RobotFramework 3.0.2
  • SeleniumLibrary 3.0.0a2

 

公式サイトの確認

GitHubを見たところ、以下のコメントがありました。

Selenium2Library 3.0 and newer extend the new SeleniumLibrary and thus contain exactly the same code and functionality. There have been lot of internal changes in the library, but external functionality provided by keywords should be fully backwards compatible. Libraries and tools using Selenium2Library internally may need to be updated to support Selenium2Library 3, though. Selenium2Library 1.8 is the latest, and last, legacy version with the old architecture and code.

Selenium2Library 3 supports Python 2.7 as well as Python 3.3 and newer. Selenium2Library 1.8 supports Python 2.6-2.7.

https://github.com/robotframework/Selenium2Library

 
そこでリンク先(https://github.com/robotframework/SeleniumLibrary)を確認したところ、たしかに今までのものが移動されていました。
https://github.com/robotframework/SeleniumLibrary

 
また、すでにdeprecatedしていた初期のライブラリについては、リポジトリ名が OldSeleniumLibrary へと変わっていました。
robotframework/OldSeleniumLibrary: Deprecated Selenium library for Robot Framework

 
PyPiを見ると、こんな感じでした。

 

影響

ライブラリ名が変わったことの影響を記載します。

pipでインストールするライブラリ名の変更

robotframework-selenium2library から robotframework-seleniumlibrary へと変わりました。

今まで

pip install robotframework-selenium2library

 
これから

現時点では移行段階のため pre などのオプションが必要ですが、将来は不要になるかと。

pip install --pre --upgrade robotframework-seleniumlibrary

 

Settingsで読み込むライブラリ名

過去のテストコードを修正しないといけないため、こちらのほうが影響が大きそうです。

今まで

Library  Selenium2Library

 
これから

Library  SeleniumLibrary

 

ドキュメントへのリンク

READMEにもありますが、ドキュメントも移動しています。

今まで

http://robotframework.org/Selenium2Library/Selenium2Library-1.8.0.html

 
これから

http://robotframework.org/SeleniumLibrary/SeleniumLibrary.html

 

自作のサンプルコード

過去に作成したサンプルコードについては、SeleniumLibrary 3.x系へとバージョンアップし、すべての動作を確認しました。
thinkAmi-sandbox/RobotFramework-sample: Robot Framewrok samples

Robot Framework + Selenium2Libraryで、リファラを書き換えるChrome拡張をWebDriverに入れてテストする

リファラによって挙動が変わるWebアプリをRobot Frameworkでテストすることがありました。

Webアプリのコードを書き換えたくないため、なにか良い方法がないかを探したところ、

を組み合わせれば良さそうでした。

その時に試した内容をメモしておきます。

 
2017/9/2追記

Selenium2Libraryですが、バージョン3からは SeleniumLibrary へと名称が変更されています。詳しくはこちらに書きました。
RobotFrameworkのSelenium2Libraryの名前が、SeleniumLibraryへと変更されてた - メモ的な思考的な

なお、本文はSelenium2Libraryのままにしてあります。

2017/9/2追記ここまで

 
目次

 

環境

 

Seleniumで開くChromeDriverに拡張を入れる 

packedとunpacked、どちらの方式の拡張を入れるか

Seleniumで使うChromeDriverに拡張を入れる方法は、ChromeDriverの公式サイトにありました。
Chrome Extensions - ChromeDriver - WebDriver for Chrome

方法としては、

の2つがあるようです。

紹介されているコードはJavaっぽいため、Pythonのコードを探したところ、前者については以下などがありました。
google chrome - Running Selenium WebDriver using Python with extensions (.crx files) - Stack Overflow

一方、後者のDesiredCapabilitiesオブジェクトの setCapability() メソッドを使う方法を調べてみましたが、それらしい事例はなく、Pythonライブラリのソースコードにもそれらしいメソッドは見当たりませんでした。
selenium/desired_capabilities.py at master · SeleniumHQ/selenium

そこで今回は、前者の crxファイルを使う方法で実装することにしました。

 

packedな拡張を作成する方法

Chrome拡張がどこにインストールされるかを調べたところ、 ~/Library/Application Support/Google/Chrome のようでした。
User Data Directory

また、Chrome拡張のID(ディレクトリ名)は、以下を参考にして確認しました。
Google Chrome のアプリや拡張機能、テーマが保存されている場所 - Qiita

そのディレクトリを見たところ、unpackedな状態だったため、何らかの方法で crxファイルを取得する必要がありました。

 
調べてみたところ、以下のページにpackedな拡張の作り方が記載されていました。
CRX Package Format - Google Chrome

ただ、pemファイルを用意するなどの手間がかかりそうなため、もっと容易な方法を探してみたところ、Chrome拡張のページからcrxファイルを取得するChrome拡張 Get CRX がありました。
Get CRX - Chrome ウェブストア

試しに Referer Control のページで使ってみたところ、crxファイルが取得できました。

今回はそのファイルを、テストを実行するディレクトリ直下に referer_control.crx として保存します。

 

Robot Frameworkで実装する

HeadlessなChromeだとChrome拡張ページが開けないため、今回は普通のChromeを使って実装します。

${options} =  evaluate  sys.modules['selenium.webdriver'].ChromeOptions()  sys

# HeadlessだとChrome拡張ページが開けない
# call method  ${options}  add_argument  --headless

# ${OUTPUT DIR}は、テストを実行するディレクトリ
call method  ${options}  add_extension  ${OUTPUT DIR}/referer_control.crx
create webdriver  Chrome  chrome_options=${options}

 

Referer Controlでリファラを書き換える

上記のままではChrome拡張を入れるだけで何も設定がされないため、Referer Controlの設定を行います。

 

Referer Controlの設定方法を調べる

以下が参考になりました。
Chromeでリファラ偽装する方法(リファラコントロールの使い方)

 

Robot Frameworkで実装する

上記の通り、Referer Controlの設定はブラウザから行うため、Robot Frameworkで実装できそうでした。

Robot Frameworkのlocatorに何を使うか悩みましたが、Chrome拡張のHTMLはそれほど変わらないだろうと考えました。

そこで、Chrome Developer Toolを使ってXPathを取得し、それをlocatorとして使いました。*1

あとは、Robot Frameworkで実装します。

今回は http://localhost:8084/referer/target というURLの場合のみ、リファラhttps://www.google.co.jp へと書き換えるようにしました。

# 「Referer Control」拡張の設定ページを開く
go to  chrome-extension://hnkcfpcejkafcihlgbojoidoihckciin/chrome/content/options.html

wait until page contains element  xpath=//*[@id="settingsTable"]/tbody/tr/td[2]/input
click element  xpath=//*[@id="settingsTable"]/tbody/tr/td[2]/input

# site filterに入力する
# 今回は、「http://localhost:8084/referer/target」というサイトであればリファラを書き換える
input text     xpath=//*[@id="settingsTable"]/tbody/tr/td[2]/input  http://localhost:8084/referer/target

# Customボタンを押す
click element  xpath=//*[@id="settingsTable"]/tbody/tr/td[8]

# Custom refererを入力する(Googleから来たことにする)
# 1秒待たないとうまくいかない
sleep  1s
input text  xpath=//*[@id="settingsTable"]/tbody/tr[5]/td[2]/table/tbody/tr[1]/td[1]/input  https://www.google.co.jp

# 適当なところをクリックして保存
click element  xpath=//*[@id="settingsTable"]/tbody/tr/td[2]/input

 

Bottleアプリの実装と動作確認

Bottleアプリの実装

上記のRobot Frameworkのテストコードが正しく動作するかを確認するため、Bottleアプリを作成して動作を確認します。

今回は、単純にリクエストヘッダの Referer を表示するだけにします。

target.py

@get('/referer/target')
@get('/referer/exclude')
def get_referer_target():
    referer = request.get_header('Referer')
    return f'<p id="referer">Referer: {referer}</p>'

 

Robot Frameworkで動作確認するコードを実装

先ほどのChrome拡張の設定に続いて以下のコードを書きます。

# リファラが書き換わるページへアクセス
go to  http://localhost:8084/referer/target
${target} =  get text  id=referer

# リファラが書き換わらないページへアクセス
go to  http://localhost:8084/referer/exclude
${exclude} =  get text  id=referer

# 検証してブラウザを閉じる
log to console  ${EMPTY}
log to console  ${target}
log to console  ${exclude}
should not be equal  ${target}  ${exclude}
close browser

 

動作確認

テストがパスしました。Chrome拡張の設定がうまくいき、リファラが書き換わっているようです。

$ robot selenium_modify_referer_test.robot 
===================================
Selenium Modify Referer Test                   
===================================
Chrome拡張でリファラを書き換えるテスト                                
Referer: https://www.google.co.jp
Referer: None
Chrome拡張でリファラを書き換えるテスト | PASS |
...

 

その他参考

Firefoxを使う場合

Firefoxを使う場合の例が以下にありました。
webdriver - setting request headers in selenium - Stack Overflow

 

Chromeコマンドライン・オプション

以下にまとまっていました。
List of Chromium Command Line Switches « Peter Beverloo

 

OpenSSLでのpemファイル作成

もしpemファイルを作る場合は、以下を参考にします。
ssl - How to create a self-signed certificate with openssl? - Stack Overflow

 

ソースコード

GitHubに上げました。 selenium2_library_sample/tests/selenium_modify_referer_test.robot ファイルが今回のテストファイルです。
thinkAmi-sandbox/RobotFramework-sample: Robot Framewrok samples

*1:該当Element上で右クリック、Copy > Copy XPathXpathを取得できます