プロジェクトがぶち当たる壁のひとつに、「リグレッションテスト」があります。これは、例えば新機能を実装したとき、他の既存機能に影響を及ぼすことがないか調べるために行うもので、デグレ(デグレード)試験とも呼ばれます。
さて、サーバーサイド・APIレベルに限れば、このリグレッションテストは自動テストフレームワークを利用することで容易にできます。JavaであればJUnitやTestNG。JavaScriptであればMochaやJasmineなどがあります。
しかし、それらのテストはあくまでもメソッドやコントローラーなどの単位で行われるということです。つまり、フロントエンドの画面に対して、クリックや文字入力をシミュレートしてくれるわけではありません。
そうすると、どうしても画面のテストは人力に頼ることになってしまいますし、莫大な工数となることは疑いようもありません。テストエビデンスなどという馬鹿馬鹿しい制度が導入されていれば尚です。
人力テストからの脱却
確かに、人力で行うテストは重要なものです。人でなければ検出できない問題などいくらでもあります。たとえばそれはレイアウトの問題であったり、CSSやフォントの問題であったりします。テストコードが間違っているかもしれません。
しかし、一度行った試験を再度繰り返して行う、リグレッションテストは別です。本来、影響が及ばないはずのところをわざわざテストするわけですから、そもそもの機能の信頼度は一定の水準を満たしているわけです。つまり、人力で行ったところで、大半はテスト項目書にOKをコピペしていくだけの作業に終始するわけです。
となれば、その工数は丸々削減できます。リグレッションテストに限っては、人間が行う手順と、テストコードが行う手順に大きな差はないからです。
JavaにSeleniumを導入する
Seleniumは、優れた自動化フレームワークです。本来は先に述べたようにリグレッションテストに使うのが一般的です。しかし、Selenium本体はテスティングフレームワークというわけではなく、あくまでブラウザを制御するライブラリにすぎません。
ですから、これとは別に使い慣れたテスティングフレームワークを利用する必要がありますが、本稿では割愛させて頂きます。
ライブラリのダウンロード
もしmavenやgradleなどのプロジェクト管理ツールを利用しているなら、ビルド設定ファイルに書き足すだけで瞬時に利用することができるようになります。
pom
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>3.7.1</version>
</dependency>
gradle
dependencies {
testCompile 'org.seleniumhq.selenium:selenium-java:3.7.1'
}
参考:SeleniumHQ Maven Information
プロジェクト管理ツールが無い場合は、こちらからzipファイルをダウンロードできますので、解凍して中のlibs配下をすべてクラスパスに紐づけてください。
ドライバファイルを用意する
以下のサイトから、テスト対象のブラウザ用のドライバファイルをダウンロードして、任意のディレクトリに格納します。
これら以外のドライバは、公式ページの「Third Party Browser Drivers」の項目からダウンロードできます。
Seleniumを用いてブラウザを操作する
コードを記述する
それでは、実際にコードを記述しましょう。非常に簡単かつシンプルなコードを記述できます。今回は、Chromeの自動化の例を記載いたします。
System.setProperty("webdriver.chrome.driver","path/to/driver"); // ドライバへのパスを記述
WebDriver driver = new ChromeDriver();
これだけでChromeをコード上から動かす準備ができてしまいました。実際に何かしてみましょう。
driver.get("http://www.google.co,jp"); // googleにページ遷移
driver.findElement(By.xpath("//*[@id=\"tsf\"]/div[2]/div[3]/center/input[2]")).click();
このコードを実行すると、googleにページ遷移した後、I’m Feeling Luckeyのボタンがクリックされます。
ところで、xpathの引数に呪文のような文字列が記述されていますが、Google Chromeの開発者ツールを利用することによって、簡単に取得することができます。
対象の要素を右クリックして、「検証」を実行すると対象の要素が表示されますので、それを右クリックして、「Copy -> Copy XPath」を選択するだけです。
findElementメソッドに渡せるByオブジェクトは、この他にもいろいろありますから、APIドキュメントを参考にしてみてください。一例を以下に例示します。
driver.findElement(By.className("class-name")); // クラス名で検索
driver.findElement(By.cssSelector(".class-name")); // CSSセレクタで検索
driver.findElement(By.id("idName")); // IDで検索
driver.findElement(By.name("password")); // nameで検索
driver.findElement(By.linkText("Join US")); // リンクの文字列で検索(完全一致)
driver.findElement(By.partialLinkText("Join US")); // リンクの文字列で検索(部分一致)
findElementメソッドが返すWebElementクラスも、さまざまなメソッドを備えています。先ほど例示したclick()メソッドをはじめ、sendKeysといったキーボードをエミュレーションするようなメソッドのほか、getSizeという要素のサイズを取得するメソッドなどを使えば、「要素が正しく表示されているか」を数値的に評価することもできます。
スクリーンショットを保存する
このほか、スクリーンショットを保存する事もできます。この機能により、たとえばテストがFailureとなった場合にスクリーンショットを残しておくことで、バグフィックスの時に活用するなどの用途が考えられます。
File file = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
OutputTypeによると、この他にbyteとbase64が指定できるようです。結果をデータベースに書き込んだりもできそうですね。
ただ、今のところは深く掘り下げて使用しているわけではありませんので、詳しい解説は割愛させていただきます。
ブラウザを終了させる
このままだと、コードの実行が終わってもブラウザはそのまま残ってしまいます。特に害はないのですが、自動テストとしては適切ではありませんから、明示的に終了させます。
driver.close();
driver.quit();
まとめ
このように、非常に簡潔な手順でSeleniumの基盤を作りあげることができました。あとはJUnitやTestNGなどのテスティングフレームワークでテストコードを記述するだけです。
自動テストは品質向上に非常に有用なフレームワークですから、有効活用してプロダクトの品質を維持しましょう!