§specs2 を使用した関数型テストの作成
Play は、関数型テストを支援する多くのクラスと便利なメソッドを提供します。これらのほとんどは、play.api.test
パッケージ、または Helpers
オブジェクトにあります。
次のものをインポートすることで、これらのメソッドとクラスを追加できます。
import play.api.test._
import play.api.test.Helpers._
§テスト用の Application
インスタンスの作成
Play は、多くの場合、実行中の Application
をコンテキストとして必要とします。デフォルトの Guice 依存性注入を使用している場合は、異なる設定、ルート、さらには追加のモジュールで構成できる GuiceApplicationBuilder
クラスを使用できます。
val application: Application = GuiceApplicationBuilder().build()
§WithApplication
アプリケーションを例に渡すには、WithApplication
を使用します。明示的な Application
を渡すことができますが、便宜上、デフォルトのアプリケーション(デフォルトの GuiceApplicationBuilder
から作成)が提供されます。
WithApplication
は組み込みの Around
ブロックであるため、独自のデータポピュレーションを提供するようにオーバーライドできます。
abstract class WithDbData extends WithApplication {
override def wrap[T: AsResult](t: => T): Result = super.wrap {
setupData()
t
}
def setupData(): Unit = {
// setup data
}
}
"Computer model" should {
"be retrieved by id" in new WithDbData {
override def running() = {
// your test code
}
}
"be retrieved by email" in new WithDbData {
override def running() = {
// your test code
}
}
}
§WithServer
テスト内で実際の HTTP スタックをテストしたい場合は、WithServer
を使用してテストサーバーを起動できます。
"test server logic" in new WithServer(app = applicationWithBrowser, port = testPort) {
override def running() = {
// The test payment gateway requires a callback to this server before it returns a result...
val callbackURL = s"http://$myPublicAddress/callback"
val ws = app.injector.instanceOf[WSClient]
// await is from play.api.test.FutureAwaits
val response =
await(ws.url(testPaymentGatewayURL).withQueryStringParameters("callbackURL" -> callbackURL).get())
response.status must equalTo(OK)
}
}
port
値には、サーバーが実行されているポート番号が含まれています。デフォルトではランダムなポートが割り当てられますが、WithServer
にポートを渡すか、システムプロパティ testserver.port
を設定することで変更できます。これは、継続的インテグレーションサーバーとの統合に役立ち、各ビルドでポートを動的に予約できます。システムプロパティ testserver.address
を使用して、テストサーバーがバインドするアドレスも構成できます。設定されていない場合、Play サーバーのデフォルトの "0.0.0.0"
を使用します。
アプリケーションはテストサーバーにも渡すことができます。これは、カスタムルートを設定して WS 呼び出しをテストする場合に役立ちます。
val appWithRoutes = GuiceApplicationBuilder()
.appRoutes { app =>
val Action = app.injector.instanceOf[DefaultActionBuilder]
({
case ("GET", "/") =>
Action {
Ok("ok")
}
})
}
.build()
"test WSClient logic" in new WithServer(app = appWithRoutes, port = 3333) {
override def running() = {
val ws = app.injector.instanceOf[WSClient]
await(ws.url("http://localhost:3333").get()).status must equalTo(OK)
}
}
§WithBrowser
ブラウザを使用してアプリケーションをテストする場合は、Selenium WebDriver を使用できます。Play は WebDriver を自動的に起動し、WithBrowser
を使用して FluentLenium が提供する便利な API でラップします。WithServer
と同様に、ポート、Application
を変更し、使用するWebブラウザを選択することもできます。
def applicationWithBrowser = {
new GuiceApplicationBuilder()
.appRoutes { app =>
val Action = app.injector.instanceOf[DefaultActionBuilder]
({
case ("GET", "/") =>
Action {
Ok("""
|<html>
|<body>
| <div id="title">Hello Guest</div>
| <a href="/login">click me</a>
|</body>
|</html>
""".stripMargin).as("text/html")
}
case ("GET", "/login") =>
Action {
Ok("""
|<html>
|<body>
| <div id="title">Hello Coco</div>
|</body>
|</html>
""".stripMargin).as("text/html")
}
})
}
.build()
}
"run in a browser" in new WithBrowser(webDriver = WebDriverFactory(HTMLUNIT), app = applicationWithBrowser) {
override def running() = {
browser.goTo("/")
// Check the page
browser.el("#title").text() must equalTo("Hello Guest")
browser.el("a").click()
browser.url must equalTo("login")
browser.el("#title").text() must equalTo("Hello Coco")
}
}
§注入
インジェクターを暗黙的な app
を介して直接使用する関数型テストが多数あります。
"test" in new WithApplication() {
override def running() = {
val executionContext = app.injector.instanceOf[ExecutionContext]
executionContext must beAnInstanceOf[ExecutionContext]
}
}
Injecting
トレイトを使用すると、これを省略できます。
"test" in new WithApplication() with play.api.test.Injecting {
override def running() = {
val executionContext = inject[ExecutionContext]
executionContext must beAnInstanceOf[ExecutionContext]
}
}
§PlaySpecification
PlaySpecification
は、Play ヘルパーメソッドと競合するデフォルトの specs2 仕様で提供されている一部のミキシンを除外する Specification
の拡張です。また、便宜上、Play テストヘルパーとタイプもミックスインします。
class ExamplePlaySpecificationSpec extends PlaySpecification {
"The specification" should {
"have access to HeaderNames" in {
USER_AGENT must be_===("User-Agent")
}
"have access to Status" in {
OK must be_===(200)
}
}
}
§ビューテンプレートのテスト
テンプレートは標準的な Scala 関数であるため、テストから実行し、結果を確認できます。
"render index template" in new WithApplication {
override def running() = {
val html = views.html.index("Coco")
contentAsString(html) must contain("Hello Coco")
}
}
§コントローラーのテスト
FakeRequest
を提供することで、任意の Action
コードを呼び出すことができます。
"respond to the index Action" in new WithApplication {
override def running() = {
val controller = app.injector.instanceOf[scalaguide.tests.controllers.HomeController]
val result = controller.index()(FakeRequest())
status(result) must equalTo(OK)
contentType(result) must beSome("text/plain")
contentAsString(result) must contain("Hello Bob")
}
}
技術的には、コントローラーを直接インスタンス化できるため、ここでは WithApplication
は必要ありません。ただし、コントローラーの直接インスタンス化は、関数型テストよりもコントローラーの単体テストに近いです。
§ルーターのテスト
自分で Action
を呼び出す代わりに、Router
に実行させることができます。
"respond to the index Action" in new WithApplication(applicationWithRouter) {
override def running() = {
val Some(result) = route(app, FakeRequest(GET, "/Bob"))
status(result) must equalTo(OK)
contentType(result) must beSome("text/html")
charset(result) must beSome("utf-8")
contentAsString(result) must contain("Hello Bob")
}
}
§モデルのテスト
SQL データベースを使用している場合は、inMemoryDatabase
を使用してデータベース接続を H2 データベースのインメモリインスタンスに置き換えることができます。
def appWithMemoryDatabase = new GuiceApplicationBuilder().configure(inMemoryDatabase("test")).build()
"run an application" in new WithApplication(appWithMemoryDatabase) {
override def running() = {
val Some(macintosh) = Computer.findById(21)
macintosh.name must equalTo("Macintosh")
macintosh.introduced must beSome[String].which(_ must beEqualTo("1984-01-24"))
}
}
§Messages API のテスト
設定を含む関数型テストの場合、最適な方法は WithApplication
を使用して、注入された MessagesApi
を取得することです。
"messages" should {
import play.api.i18n._
implicit val lang = Lang("en-US")
"provide default messages with the Java API" in new WithApplication() with Injecting {
override def running() = {
val javaMessagesApi = inject[play.i18n.MessagesApi]
val msg = javaMessagesApi.get(new play.i18n.Lang(lang), "constraint.email")
msg must ===("Email")
}
}
"provide default messages with the Scala API" in new WithApplication() with Injecting {
override def running() = {
val messagesApi = inject[MessagesApi]
val msg = messagesApi("constraint.email")
msg must ===("Email")
}
}
}
設定をカスタマイズする必要がある場合は、DefaultMessagesApiProvider
を直接使用するかわりに、GuiceApplicationBuilder
に設定値を追加する方が適切です。
次へ: Guice を使用したテスト
このドキュメントに誤りを見つけましたか?このページのソースコードは こちらにあります。ドキュメントガイドライン を読んでから、プルリクエストを送信して自由に貢献してください。質問やアドバイスを共有したいですか?コミュニティフォーラム にアクセスして、コミュニティとの会話を開始してください。