連載
» 2013年09月09日 18時00分 公開

Javaの常識を変えるPlay framework入門(6):Playの充実したテスト環境で行う5種のテスト (3/3)

[今泉俊幸,ビーブレイクシステムズ]
前のページへ 1|2|3       

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かどうかを検証しています。

ブラウザテスト

 最後に、実際にブラウザを使ってテストサーバにアクセスし、処理を実行させる形式のテストを書いていきます。ブラウザテストの手順は以下の通りです。

  1. テスト用のWebサーバを起動
  2. テストメソッドに渡されるブラウザのドライバクラスを使って、Webページへのアクセス、入力を行う
  3. 同じくブラウザのドライバクラスを使って、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が持つメソッドは以下のようなものがあります。

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接続先をH2DBのインメモリに変更する例

 なお、上記のようにDB接続先をインメモリに変更するだけであれば、自分でMapに値を詰めずとも、inMemoryDatabaseメソッドを使うことで簡単に作成が可能です。

@Test
public void testInMemory() {
	running(fakeApplication(inMemoryDatabase()), new Runnable() {
		...
	});
}

次回はPlayアプリをPaaSクラウドにデプロイ

 ビューとコントローラに対するテストと、実際のブラウザを使ったテストを見てきましたが、Play framework はWebアプリであっても実に簡易なコードでテストが書けるということが理解できたのではないでしょうか。

 次回は作成したアプリケーションをHerokuにデプロイし、Web上に公開する方法を紹介します。

著者プロフィール

今泉俊幸(いまいずみとしゆき)


2011年より、株式会社ビーブレイクシステムズに在籍。あるべきものをあるべき姿に、をモットーに、保守しやすいプログラムを書くため日々邁進中。


前のページへ 1|2|3       

Copyright © ITmedia, Inc. All Rights Reserved.

編集部からのお知らせ

8月8日10時30分〜16時30分の間、システムメンテナンスのため記事の一部表示や資料のダウンロードができなくなります。ご理解のほどよろしくお願いいたします。

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。