仕事で使うかもしれなさそう…ということで、Selenium WebDriverを使ってみました。初めて触ってみたのですが、けっこう便利そうですね。
とりあえず、使ってみる
公式ドキュメントの写経+Maven、JUnitと一緒に使ってみることにします。
こんなpom.xmlを用意。
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>webdriver.example</groupId> <artifactId>webdriver-example</artifactId> <packaging>jar</packaging> <version>0.0.1-SNAPSHOT</version> <name>webdriver-example</name> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.0</version> <configuration> <source>1.7</source> <target>1.7</target> <fork>true</fork> </configuration> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <dependency> <groupId>org.seleniumhq.selenium</groupId> <artifactId>selenium-java</artifactId> <version>2.28.0</version> <scope>test</scope> </dependency> </dependencies> </project>
次いで、公式のドキュメントを参考にGoogleへアクセスするコードを実装。
http://seleniumhq.org/docs/03_webdriver.jsp#introducing-the-selenium-webdriver-api-by-example
import static org.junit.Assert.*; import static org.hamcrest.CoreMatchers.*; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.firefox.FirefoxDriver; import org.openqa.selenium.support.ui.ExpectedCondition; import org.openqa.selenium.support.ui.WebDriverWait; public class GoogleTest { WebDriver driver; @Before public void setUp() { driver = new FirefoxDriver(); } @After public void tearDown() { driver.quit(); } @Test public void Googleでテストしてみる() throws Exception { // Googleへアクセス driver.get("http://www.google.co.jp/"); // ページのタイトルを確認 assertThat(driver.getTitle(), is("Google")); // DOMからname=qの要素を探す WebElement element = driver.findElement(By.name("q")); // 見つけた要素にキーワードを入力してサブミット element.sendKeys("Cheese!"); element.submit(); // 描画し終わるまで、最大10秒待つ // 終了の判定条件は、untilメソッドに渡す内容で記述 (new WebDriverWait(driver, 10)).until(new ExpectedCondition<Boolean>() { public Boolean apply(WebDriver d) { return d.getTitle().toLowerCase().startsWith("cheese!"); } }); // ページのタイトルを確認 assertThat(driver.getTitle(), is("cheese! - Google 検索")); } }
WebDriverは、Firefoxのものを使用しています。WebDriverのインスタンスを中心にプログラミングしていく感じなんですね。DOMから要素を抜く時は、Byを使え、と。
WebDriverのインスタンスは、とりあえず@Beforeで初期化して、@Afterで破棄しています。
一応Mavenでやっているので、
$ mvn test
で実行できます。Firefoxが起動してきて、Googleのキーワード入力欄に「Cheese!」と入力して画面遷移、そしてFirefoxが終了するところまでが確認できます。
ちょっと面白いです。
キャプチャを取る
使用しているDriverが、org.openqa.selenium.TakesScreenshotインターフェースを実装していれば、getScreenshotAsメソッドでキャプチャが取得できるようです。
これを使用するように、先ほどのテストケースをコピーして別途作成してみました。
import static org.junit.Assert.*; import static org.hamcrest.CoreMatchers.*; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.text.SimpleDateFormat; import java.util.Date; import org.junit.After; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import org.openqa.selenium.By; import org.openqa.selenium.OutputType; import org.openqa.selenium.TakesScreenshot; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.firefox.FirefoxDriver; import org.openqa.selenium.support.ui.ExpectedConditions; import org.openqa.selenium.support.ui.WebDriverWait; public class GoogleCaptureTest { static Path captureDirectory; WebDriver driver; @BeforeClass public static void setUpClass() throws Exception { captureDirectory = Paths.get(new SimpleDateFormat("'capture'/yyyyMMddHHmmss").format(new Date())); Files.createDirectories(captureDirectory); } @Before public void setUp() { driver = new FirefoxDriver(); } @After public void tearDown() { driver.quit(); } @Test public void Googleでキャプチャーしてみる() throws Exception { driver.get("http://www.google.co.jp/"); assertThat(driver.getTitle(), is("Google")); capture(driver, "capture1.png"); WebElement element = driver.findElement(By.name("q")); element.sendKeys("Cheese!"); element.submit(); (new WebDriverWait(driver, 10)).until(ExpectedConditions.titleContains("Google 検索")); assertThat(driver.getTitle(), is("cheese! - Google 検索")); capture(driver, "capture2.png"); } public void capture(WebDriver driver, String fileName) throws Exception { if (driver instanceof TakesScreenshot) { TakesScreenshot screen = (TakesScreenshot)driver; Path capture = captureDirectory.resolve(fileName); Files.write(capture, screen.getScreenshotAs(OutputType.BYTES)); } } }
アサーションは、先の例と同じです。あと、WebDriverWaitを使った待機の部分は、ExpectedConditionsを使ってちょっと端折っています。
とりあえず、最初に@BeforeClassでキャプチャ保存用のディレクトリを作っておいて、各画面描画時にキャプチャを取得するようにしています。
キャプチャしているのは、このメソッドですね。
public void capture(WebDriver driver, String fileName) throws Exception { if (driver instanceof TakesScreenshot) { TakesScreenshot screen = (TakesScreenshot)driver; Path capture = captureDirectory.resolve(fileName); Files.write(capture, screen.getScreenshotAs(OutputType.BYTES)); } }
WebDriverのインスタンスがTakesScreenshotにキャスト可能だったらキャストして、TakesScreenshot#getScreenshotAsメソッドでキャプチャを取得します。取得形式は、OutputTypeで指定できるようです。
今回は、java.nio.file.Files#writeにそのまま渡してしまえと思ってOutputType.BYTESを選びました。
実行すると、Mavenプロジェクト直下の「capture/実行日時」ディレクトリ配下にキャプチャができます。あ、形式はpngですね。
ブラウザを起動するので重たいのですが(HtmlUnitDriverを使えという話もあるようですが、キャプチャは取れない…)、けっこう面白いですね、コレ。
参考)
公式ドキュメント
http://seleniumhq.org/docs/03_webdriver.jsp#htmlunit-driver
Javadoc
http://selenium.googlecode.com/svn/trunk/docs/api/java/index.html
http://www.atmarkit.co.jp/ait/articles/1210/05/news104.html
http://www.atmarkit.co.jp/ait/articles/1211/07/news009.html