Playの充実したテスト環境で行う5種のテスト:Javaの常識を変えるPlay framework入門(6)(3/3 ページ)
サーブレット/JSPを基にする重厚長大なJavaのWeb開発のイメージを変える軽量フレームワーク「Play」について解説し、Webアプリの作り方を紹介する入門連載。今回は、シンプルな単体テストに加え、ビューやコントローラ、routeファイルのテスト、ブラウザテスト、テスト用の環境設定について解説します。
routeファイルのテスト
先ほどのコントローラのテストでは、POST/GETの区別なく、コントローラのメソッド呼び出しを行っていました。しかし、routeファイルでは、POSTでアクセスした場合のみ呼ばれるようにnameResultメソッドが定義されています。
そこで、GETでアクセスした場合と、POSTでアクセスした場合をテストしてみます。testフォルダにRouteTestクラスを作成してください。
import static org.fest.assertions.Assertions.*; import static play.test.Helpers.*; import org.junit.Test; import play.mvc.Result; public class RouteTest { @Test public void testNameResultPost(){ running(fakeApplication(), new Runnable() { @Override public void run() { Result result = routeAndCall(fakeRequest(POST, "/name")); assertThat(result).isNotNull(); } }); } @Test public void testNameResultGet(){ running(fakeApplication(), new Runnable() { @Override public void run() { Result result = routeAndCall(fakeRequest(GET, "/name")); assertThat(result).isNull(); } }); } }
routeファイルのテストを行う際は、callActionメソッドの代わりにrouteAndCallメソッドを利用し、HTTPメソッドとアクセスするURIを指定します。routeAndCallメソッドの返り値は、コントローラのテストの際と同様にResult型で返されます。
また、routeファイルに定義されていないHTTPメソッド/URIを指定した場合は、resultはnullとなります。そのため、GETメソッドで/nameをアクセスしたときはresultがnullかどうかを検証しています。
ブラウザテスト
最後に、実際にブラウザを使ってテストサーバにアクセスし、処理を実行させる形式のテストを書いていきます。ブラウザテストの手順は以下の通りです。
- テスト用のWebサーバを起動
- テストメソッドに渡されるブラウザのドライバクラスを使って、Webページへのアクセス、入力を行う
- 同じくブラウザのドライバクラスを使って、Webページの要素を取得し、値の検証を行う
テストサーバの起動
まずは、テストサーバを起動し、トップページにアクセスするだけのコードを書いてみます。以下のクラスを作成してください。
import static org.fest.assertions.Assertions.*; import static play.test.Helpers.*; import org.junit.Test; import org.openqa.selenium.Firefox.FirefoxDriver; import play.libs.F.Callback; import play.test.TestBrowser; public class IntegrationTest { @Test public void testTop() { running(testServer(3333), FirefoxDriver.class, new Callback<TestBrowser>() { public void invoke(TestBrowser browser) { browser.goTo("http://localhost:3333/top"); } }); } }
ブラウザテストでも、コントローラのテスト同様に、runningメソッドを用いてplay runを実行した場合と同じ状況にする必要があります。
ただし、今回はブラウザからのアクセスができるよう、ポートを指定する必要があります。また、どのブラウザでテストするのか、ブラウザのドライバクラスも指定する必要があります。
そのため、runningメソッドの第1引数は、fakeApplicationメソッドの代わりにtestServerメソッドを使います。テストで使うポートはtestServerメソッドの引数に指定します。
第2引数には、テストを行うドライバクラスを指定します。今回はFirefox用のドライバクラスを渡しているので、テストを実行すると自動でFirefoxが立ち上がります。
第3引数には、テストコードを実行するクラスを渡します。コントローラのテストではRunnableインターフェイスを実装したクラスを渡していましたが、今回はブラウザ操作を行うためのドライバを受け取る必要があるため、Callbackインターフェイスを実装するようにします。
テストコードはこのクラスのinvokeメソッドの中に記述し、ブラウザに対する操作は、引数に渡されてくるTestBrowserクラスを利用して行います。
ブラウザに対する操作
TestBrowserクラスのメソッドは以下のようなものがあります。
メソッド | 機能 |
---|---|
Fluent goTo(String address) | addressのページを開く。返り値はテストブラウザ自身となる |
String title() | 現在のページのタイトルを返す |
String url() | 現在のページのURLを返す |
FluentList $(String cssSelector) | cssSelectorで示す要素を取得する |
上記の中で最も重要なものが$メソッドです。$メソッドは、引数にCSSセレクタを指定し、そのCSSセレクタでヒットした要素をFluentList型で返します。
FluentListは、ヒットした要素をFluentWebElement型で保持しおり、firstメソッドやgetメソッドで要素を取得できます。
テストではこのFluentWebElementオブジェクトを使ってブラウザ上のテキストボックスの入力や、ボタンの押下を行います。
FluentWebElementが持つメソッドは以下のようなものがあります。
メソッド | 機能 |
---|---|
text (String str) | 選択された要素に引数の値を入力する |
click() | 選択された要素をクリックする |
getTextk() | 選択された要素の文字列を取得する |
isEnabledk() | 選択された要素が有効かどうかを返す |
なお、FluentListについても、上記のメソッドは定義されています。そのため、$メソッドで指定した要素全てについて同一の操作を行って問題なければ、FluentListの中からわざわざFluentWebElementを取得せずに、FluentListに対し上記メソッドを呼び出すことで簡潔にコードが記述できます。
上記メソッドを用いて、トップページにアクセスし、名前を入力して占うボタンをクリックするまでをテストするコードは以下の通りです。
public class IntegrationTest { @Test public void test() { running(testServer(3333),FirefoxDriver.class ,new Callback<TestBrowser>() { public void invoke(TestBrowser browser) { browser.goTo("http://localhost:3333/top"); assertThat(browser.title()).isEqualTo("占い"); browser.$("input[name=\"name\"]").text("太郎"); browser.$("input[type=\"submit\"]").click(); assertThat(browser.title()).isEqualTo("名前占い結果"); assertThat(browser.$("*").first().getText()).contains("太郎"); } }); } }
補足 ブラウザテストが動作しない場合の対応
テストで用いるブラウザのバージョンが新しい場合、テスト実行時にブラウザの操作がうまくいかない場合があります。
この原因として、Play frameworkがあらかじめ用意しているドライバクラスが最新のバージョンに対応していないことが考えられます。
このような場合には、以下のURLから最新のSelenium Serverをダウンロードし、lib以下に配置することで対応が可能です。
テスト用の環境設定
上記でテストしたコントローラには、DBアクセスのコードが含まれていませんでした。しかし、DBアクセスがある場合は、テスト用のDBに接続先を変更する必要があるでしょう。その場合は、テストのたびにapplication.confを直接書き換える必要はなく、プログラム上でテストケースごとに接続先を変更可能です。
今までのサンプルでは、ダミーのアプリケーションを作成する際、fakeApplicationメソッドを引数なしで呼び出していました。このメソッドの引数に、Mapを渡すことで、application.confの設定を上書きできます。
@Test public void testMap() { Map<String,String> paramMap = new HashMap<String, String>(); paramMap.put("db.default.driver", "org.h2.Driver"); paramMap.put("db.default.url", "jdbc:h2:mem:play"); running(fakeApplication(paramMap), new Runnable() { @Override public void run() { //DBアクセスを伴うテスト } }); }
なお、上記のようにDB接続先をインメモリに変更するだけであれば、自分でMapに値を詰めずとも、inMemoryDatabaseメソッドを使うことで簡単に作成が可能です。
@Test public void testInMemory() { running(fakeApplication(inMemoryDatabase()), new Runnable() { ... }); }
次回はPlayアプリをPaaSクラウドにデプロイ
ビューとコントローラに対するテストと、実際のブラウザを使ったテストを見てきましたが、Play framework はWebアプリであっても実に簡易なコードでテストが書けるということが理解できたのではないでしょうか。
次回は作成したアプリケーションをHerokuにデプロイし、Web上に公開する方法を紹介します。
Copyright © ITmedia, Inc. All Rights Reserved.
関連記事
- Scala+Play 2.0でWebアプリ開発入門(8):Playのグローバルな設定&spec2でBDDなテスト
2.0からScalaに対応したWebアプリ開発の人気軽量フレームワーク「Play」について解説し、Webアプリの作り方を紹介する入門連載。今回は、アプリ起動/停止前後やエラー発生時などで使えるGlobalオブジェクトや、さまざまなテストについて解説。Selenium WebDriverを使ったブラウザテストも。 - Selenium WebDriverでWebアプリのテストが変わる(前編):iPhone/Android含むブラウザ自動テストの最終兵器Selenium WebDriverとは
Chrome、Firefox、Internet Explorer、Opera、Android、iOSといったブラウザに対応し、Java、C#、Python、Rubyが使えるWebテスト自動化ツールの3つの特徴と環境、実装方法を簡単に紹介 - DevOps時代の開発者ための構成管理入門(4):膨大なビルド・テストで泣かないための継続的統合/CI実践ノウハウ
「DevOps」という言葉にもあるように、ソフトウェア構成管理は、インフラ運用に取り入れられるなど、変わりつつある時代だ。本連載では、そのトレンドにフォーカスして、現在のソフトウェア開発に有効な構成管理のノウハウをお伝えする。今回は、Jenkinsをはじめ、ツールが格段に使いやすくなってきた継続的インテグレーションについて、概要やメリットに加え、実践ノウハウを事例とともに紹介。