はじめに
今回はSelenium WebDriverをご紹介します。ブラウザ操作を自動化する際には最適な仕組みです。Webシステムのend-to-endテストを自動化する際には、ブラウザ操作が必要になることがあります。そんな時にSelenium WebDriverはとても便利です。
Selenium
Seleniumとは、ブラウザをプログラムで動かすフレームワークです。この仕組みを使うことで、ユーザーテストなど、様々な処理を自動化できます。現在のところ、Seleniumは以下のWebブラウザを制御できます(公式サイト)。
- Internet Explorer
- Firefox
- Chrome
- Opera
- Android標準Webブラウザ
- Safari (iPhone標準Webブラウザ)
実際に使用する際には、以下の2つの仕組みのどちらかを使用します。
Selenium IDEはFirefoxのアドオンです。Firefox上でユーザー操作を記録します。この処理を再度実行したり、WebDriverのコードへ変換できます。バグを再現させる場合など、手軽に使えて非常に便利です。
Selenium WebDriverとは、ブラウザの拡張機能やOSネイティブの機能を使ってブラウザを操作するライブラリ群、もしくはその仕組みのことです。プログラムに記述した通りにブラウザを操作できます。Java、Python、Ruby、C#のいずれかを使用します(公式提供)。ブラウザを使用した自動テストを詳細に作成する場合などに便利です。
今回は、ブラウザ制御を全て自動化できるSelenium WebDriverを使ってみます。Javaを使って、以下の2つのことをしてみましょう。
- PC上でのブラウザ操作
- Android端末(実機)上でのブラウザ操作
画面遷移、JavaScriptのクリックイベント実行、JUnitとの組み合わせなども試してみます。
プロジェクト作成
まずは、Javaのパッケージを下記サイトからダウンロードします。2013年7月5日現在では、selenium-java-2.33.0.zipが最新版のようです。
http://docs.seleniumhq.org/download/
ダウンロードしたファイルを展開すると、無意味に深い階層が現れます。最後のselenium-2.33.0ディレクトリをそのままeclipseインストールディレクトリのdropinsディレクトリへ移動しておきます。
- selenium-2.33.0
- └
selenium-2.33.0 └ selenium-2.33.0 ├ libs ├ selenium-java-2.33.0.jar └ selenium-java-2.33.0-srcs.jar
- プロジェクトを右クリック
- Java Build Pathを選択
- Add External JARsをクリック
- eclipse/dropins内のselenium-java-2.33.0.jarとlibs内の全てのjarを追加
ここまで出来たら、後はコードを書いてブラウザを動かしてみるだけです!
PCブラウザ操作
ブラウザの起動・終了
まずは、ブラウザを単純に開いて閉じることをしてみましょう。ここではアシアルのサイトを見てみます。今回はFirefoxを使います。
- package
jp.co.asial.test; - import
org.openqa.selenium.WebDriver; - import
org.openqa.selenium.firefox.FirefoxDriver; - public
class AsialHpTest { public static void main(String[] args) { WebDriver driver = new FirefoxDriver(); driver.get("http://www.asial.co.jp"); driver.quit(); } - }
画面遷移
せっかくブラウザを開いたのだから、何らかの操作をしてみます。画面のリンクをクリックし、別の画面へ遷移してみます。下記のコードでは、各処理の間に1秒間処理を止めています。これを入れないと、処理が速すぎて何をしているかよく分からないためです。もちろん、テストを運用する時には外します。
- package
jp.co.asial.test; - import
org.openqa.selenium.By; - import
org.openqa.selenium.WebDriver; - import
org.openqa.selenium.WebElement; - import
org.openqa.selenium.firefox.FirefoxDriver; - public
class AsialHpTest { public static void main(String[] args) { WebDriver driver = new FirefoxDriver(); driver.get("http://www.asial.co.jp"); sleep(1000); driver.findElement(By.cssSelector("ul.globalMenuNormal li:first-child")).click(); sleep(1000); driver.quit(); } private static void sleep(int microtime) { try { Thread.sleep(microtime); } catch (InterruptedException e) { e.printStackTrace(); } } - }
ちなみに、WebDriverのfindElement()メソッドでは、WebElementインタフェースを実装したオブジェクトを取得できます。そのオブジェクトを使えば、要素が現在見えているのか否か、どこに表示されているか、要素の表示サイズ、などを取得できます。例えば以下のように記述できます。
- WebElement
element = driver.findElement(By.cssSelector("ul.globalMenuNormal li:last-child")); - System.out.println("displayed
= " + String.valueOf(element.isDisplayed())); - System.out.println("enabled
= " + String.valueOf(element.isEnabled())); - System.out.println("position
= " + element.getLocation()); - System.out.println("dimension
= " + element.getSize()); - System.out.println("font-size
= " + element.getCssValue("font-size"));
JavaScript実行
次に、JavaScriptのクリックイベントを実行してみます。アシアルのサイトでは、サイト上部の画像の両脇のボタンを押すことで、画像を左右に移動して変更できます。プログラムからこの操作をしてみたいと思います。
- package
jp.co.asial.test; - import
org.openqa.selenium.By; - import
org.openqa.selenium.WebElement; - import
org.openqa.selenium.firefox.FirefoxDriver; - import
org.openqa.selenium.remote.RemoteWebDriver; - public
class AsialHpTest { public static void main(String[] args) { RemoteWebDriver driver = new FirefoxDriver(); driver.get("http://www.asial.co.jp"); sleep(1000); WebElement element = driver.findElement(By.cssSelector("ul.flex-direction-nav a.prev")); for (int i=0; i<5; i++) { driver.executeScript("arguments[0].click();", element); sleep(1000); } driver.quit(); } private static void sleep(int microtime) { // 省略 } - }
上記コードにて、element(WebElementオブジェクト)のclick()メソッドを実行するとエラーとなります。
もちろん、WebDriverインタフェースの形でも同様のことをできます。
- public
class AsialHpTest { public static void main(String[] args) { WebDriver driver = new FirefoxDriver(); JavascriptExecutor executor = (JavascriptExecutor)driver; ... for (int i=0; i<5; i++) { executor.executeScript(...); } ... } ... - }
スクリーンショット
スクリーンショットも軽々と撮れます。テスト結果の検証物件として納品する場合に便利そうです。
- package
jp.co.asial.test; - import
java.io.File; - import
java.io.IOException; - import
org.apache.commons.io.FileUtils; - import
org.openqa.selenium.OutputType; - import
org.openqa.selenium.TakesScreenshot; - import
org.openqa.selenium.WebDriver; - import
org.openqa.selenium.WebDriverException; - import
org.openqa.selenium.firefox.FirefoxDriver; - public
class AsialScreenShot { public static void main(String[] args) { WebDriver driver = new FirefoxDriver(); driver.get("http://www.asial.co.jp"); try { FileUtils.copyFile( ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE), new File("path/to/file")); } catch (WebDriverException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } driver.quit(); } - }
+JUnit
PCブラウザ操作の最後に、JUnitと組み合わせて使用してみます。下記コードをRun As => JUnit Testから実行します(Eclipse JUnit Launcher)。JUnitがテストケースを順番に実行してくれます。また、Assertを使用して画面URLや各要素を確認することもできます。ここまで来ると、Selenium WebDriverを使えばテスト自動化もサクサクできそうな感じがします。
- package
jp.co.asial.test; - import
org.junit.After; - import
org.junit.Assert; - import
org.junit.Before; - import
org.junit.Test; - import
org.openqa.selenium.By; - import
org.openqa.selenium.WebDriver; - import
org.openqa.selenium.firefox.FirefoxDriver; - public
class AsialHpJUnitTest { private WebDriver driver; @Before public void beforeTest() { driver = new FirefoxDriver(); } @After public void afterTest() { sleep(1000); // 1秒後にブラウザを閉じる(動きを確認するため) driver.quit(); } // トップ画面を開くだけ @Test public void open() { driver.get("http://www.asial.co.jp"); } // スクール画面へ遷移する @Test public void moveToSchoolPage() { driver.get("http://www.asial.co.jp"); driver.findElement(By.cssSelector("ul.globalMenuNormal li:last-child")).click(); Assert.assertEquals("http://www.asial.co.jp/school/", driver.getCurrentUrl()); } private void sleep(int microtime) { try { Thread.sleep(microtime); } catch (InterruptedException e) { e.printStackTrace(); } } - }
Androidブラウザ操作
最後にAndroid端末上でブラウザを操作してみます。AndroidDriverを使うことで、自分達のサイトがAndroidブラウザ上で正しく動いているか、自動化されたend-to-endテストを実行できます。多種多様なAndroid端末が出回っているため、これが出来るととても楽になりそうです。
Androidでのブラウザ操作もしくはテストには2つの方法があります(参考)。
- リモートサーバを使用する方法
- Androidテストフレームワークを使用する方法
前者は、様々な端末で同じテストを実行したい場合に使うと便利です。後者は、既にAndroidテストフレームワークを使用ていて、かつ特定の端末で素早いテストを実行したい場合に便利です。今回は前者の方法でブラウザ操作を実行してみたいと思います。
PC・端末の設定
リモートサーバといっても、server=Android端末、client=自分のPCという構成です。Android端末とPCをそれぞれ設定していきます。端末の設定はとても簡単で、3つのことをするだけです。
- 端末をデバッグ可能モードでPCへUSB接続
- Androidアプリ「WebDriver」をAndroid端末へインストール
- WebDriverアプリを起動
Androidアプリ「WebDriver」がリモートサーバーとなるアプリケーションです。このアプリを使用してブラウザ操作を行います(正確にはWebView)。以下のサイトから、android-server-2.32.0.apkをダウンロードしてインストールします。
https://code.google.com/p/selenium/downloads/list
現在のところ、Android2.3.x、3.x、4.0.x以上で使用可能です。インストールが終わったら、アプリを起動します。後はUSBでPCへ接続し、eclipseから認識できていれば大丈夫です。
次にPCの設定を行います。PCの設定は以下の2つです。
- Android SDK のインストール
- ABD用USBドライバのインストール
- ポートフォワード設定
Android SDKとUSBドライバのインストールはSDK Managerから実行できます。ポートフォワード設定を行うには、端末のデバイスIDが必要です。上記のように端末をPCに接続した状態で、eclipseのDDMSからデバイスIDを確認できます。もしくはadbコマンドを以下のように実行すると、PCに接続している端末のデバイスID(16桁)を取得できます。
- $
adb devices
- $
adb -s [DeviceId] forward tcp:8080 tcp:8080
ブラウザ操作
では、Android端末のブラウザ操作を行ってみます。アシアルのサイトを表示し、上部リンクの位置等をコンソールに出力します。その後、200px上部へスクロールを実施。先のリンクの情報を再度コンソールに出力(位置情報が変わっている)。最後に「セミナー&スクール」の画面へ遷移します。
- package
jp.co.asial.test; - import
org.openqa.selenium.By; - import
org.openqa.selenium.WebDriver; - import
org.openqa.selenium.WebElement; - import
org.openqa.selenium.android.AndroidDriver; - public
class AsialHpAndroidTest { public static void main(String[] args) { AndroidDriver driver = new AndroidDriver(); driver.get("http://www.asial.co.jp"); check(driver, "ul.globalMenuNormal li:last-child"); sleep(1000); driver.getTouch().scroll(0, 200); check(driver, "ul.globalMenuNormal li:last-child"); sleep(1000); driver.findElementByCssSelector("ul.globalMenuNormal li:last-child").click(); System.out.println("Page title: " + driver.getTitle()); System.out.println("Page URL: " + driver.getCurrentUrl()); } private static void check(final WebDriver driver, final String selector){ final WebElement element = driver.findElement(By.cssSelector(selector)); System.out.println(selector); System.out.println("displayed = " + String.valueOf(element.isDisplayed())); System.out.println("enabled = " + String.valueOf(element.isEnabled())); System.out.println("position = " + element.getLocation()); System.out.println("dimension = " + element.getSize()); System.out.println("font-size = " + element.getCssValue("font-size")); System.out.println(""); } private static void sleep(int microtime) { try { Thread.sleep(microtime); } catch (InterruptedException e) { e.printStackTrace(); } } - }
- ul.globalMenuNormal
li:last-child - displayed
= true - enabled
= true - position
= (168, 80) <== スクロール前 - dimension
= (136, 32) - font-size
= 13px - ul.globalMenuNormal
li:last-child - displayed
= true - enabled
= true - position
= (168, -120) <== スクロール後 - dimension
= (136, 32) - font-size
= 13px - Page
title: PHP, HTML, Linux 講座 : セミナー&スクール | アシアル株式会社 - Page
URL: http://www.asial.co.jp/school/
- driver.getCapabilities().getBrowserName();
// android - driver.getCapabilities().getVersion();
// API Level
おわりに
Selenium WebDriverをPCブラウザとAndroidブラウザの両方に対して使ってみました。簡単に使用でき、ブラウザ内の操作や要素の情報も容易に取得できます。たまにブラウザ操作が失敗することが玉に瑕ですが、テストの自動化には最適だと思います。軽くでも試してみると、開発の幅が広がると思います。