簡単・便利、ブラウザの自動操作!~Selenium WebDriver~
はじめに
今回はSelenium WebDriverをご紹介します。ブラウザ操作を自動化する際には最適な仕組みです。Webシステムのend-to-endテストを自動化する際には、ブラウザ操作が必要になることがあります。そんな時にSelenium WebDriverはとても便利です。
Selenium
Seleniumとは、ブラウザをプログラムで動かすフレームワークです。この仕組みを使うことで、ユーザーテストなど、様々な処理を自動化できます。現在のところ、Seleniumは以下のWebブラウザを制御できます(公式サイト)。
- Internet Explorer
- Firefox
- Chrome
- Opera
- Android標準Webブラウザ
- Safari (iPhone標準Webブラウザ)
実際に使用する際には、以下の2つの仕組みのどちらかを使用します。
今回は、ブラウザ制御を全て自動化できる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プロジェクトをeclipseで作成し、SeleniumのJARファイルをプロジェクトへ追加します。JARの追加方法は以下の通りです。
- プロジェクトを右クリック
- Java Build Pathを選択
- Add External JARsをクリック
- eclipse/dropins内のselenium-java-2.33.0.jarとlibs内の全てのjarを追加
ここまで出来たら、後はコードを書いてブラウザを動かしてみるだけです!
- プロジェクトディレクトリへselenium-2.33.0ディレクトリをコピー
- プロジェクトを右クリック
- Java Build Pathを選択
- Add JARsをクリック
- プロジェクト内の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();
}
}
WebDriverのget()メソッドで画面を開き、quite()で閉じます。後は、Java Applicationとして実行します。すると、しばらくしてFirefoxが立ち上がり、アシアルのサイトが表示され、すぐにブラウザが閉じると思います。起動するまでに若干時間がかかります。
画面遷移
せっかくブラウザを開いたのだから、何らかの操作をしてみます。画面のリンクをクリックし、別の画面へ遷移してみます。下記のコードでは、各処理の間に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()メソッドとBy.cssSelector()メソッドを使ってCSSセレクタから対象要素(WebElement)を取得しています。そして、その要素(Aタグ)をクリックしています。WebDriverがこのクリックをブラウザ上で実行する ことで、実際に画面遷移が行われます。JavaScriptを使えるエンジニアであれば、サクサク記述できると思います。
ちなみに、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)
{
// 省略
}
}
ポイントは、RemoteWebDriverのexecuteScriptメソッドを使用している点です。RemoteWebDriverはWebDriverインタフェースを実装したクラスです。さらに、RemoteWebDriverはJavascriptExecutorインタフェースも実装しており、ここからJavaScriptを処理できます。FirefoxDriverはRemoteWebViewのサブクラスです。
上記コードにて、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桁)を取得できます。
<pre wp-pre-tag-8=""></pre>
nbsp;adb devices
ポートフォワードの設定は次の通りです。[DeviceId]の部分に端末のデバイスIDを入れます。
<pre wp-pre-tag-9=""></pre>
nbsp;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();
}
}
}
コンソールへの出力結果は次のようになります。positionのy座標が200減っていることがわかります。
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ブラウザの両方に対して使ってみました。簡単に使用でき、ブラウザ内の操作や要素の情報も容易に取得できます。たまにブラウザ操作が失敗することが玉に瑕ですが、テストの自動化には最適だと思います。軽くでも試してみると、開発の幅が広がると思います。