Documentation

§ScalaTest による機能テストの記述

Playには、機能テストを支援する、多くのクラスや便利なメソッドが用意されています。これらの大半は、play.api.test パッケージか Helpers オブジェクトに含まれています。ScalaTest + Play 統合ライブラリは、この ScalaTest のテスト支援に基づいています。

すべての Play 組み込みのテスト支援と ScalaTest + Play は、次のインポートによって利用できます。

import org.scalatest._
import play.api.test._
import play.api.test.Helpers._
import org.scalatestplus.play._

§FakeApplication

Play では頻繁に実行中の Application をコンテキストとして実行する必要がありますが、これはたいてい play.api.Play.current によって提供されます。

テスト用の環境を提供するために、Play は FakeApplication クラスを提供します。このクラスは、異なる Global オブジェクト、追加の設定、追加のプラグインによって構成されています。

val fakeApplicationWithGlobal = FakeApplication(withGlobal = Some(new GlobalSettings() {
  override def onStart(app: Application) { println("Hello world!") }
}))

テストクラスの中の、すべてあるいはほとんどのテストが FakeApplication を必要とし、すべて同一の FakeApplication を共用可能な場合は、OneAppPerSuite トレイトをミックスインします。app フィールドから FakeApplication にアクセスできます。FakeApplication のカスタマイズが必要になったら、この例に示すように app をオーバーライドして下さい。

class ExampleSpec extends PlaySpec with OneAppPerSuite {

  // Override app if you need a FakeApplication with other than
  // default parameters.
  implicit override lazy val app: FakeApplication =
    FakeApplication(
      additionalConfiguration = Map("ehcacheplugin" -> "disabled")
    )

  "The OneAppPerSuite trait" must {
    "provide a FakeApplication" in {
      app.configuration.getString("ehcacheplugin") mustBe Some("disabled")
    }
    "start the FakeApplication" in {
      Play.maybeApplication mustBe Some(app)
    }
  }
}

同一の FakeApplication を共有するのではなく、それぞれのテストで独自の FakeApplication を取得する必要がある場合は、代わりに OneAppPerTest を使用します。

class ExampleSpec extends PlaySpec with OneAppPerTest {

  // Override app if you need a FakeApplication with other than
  // default parameters.
  implicit override def newAppForTest(td: TestData): FakeApplication =
    FakeApplication(
      additionalConfiguration = Map("ehcacheplugin" -> "disabled")
    )

  "The OneAppPerTest trait" must {
    "provide a new FakeApplication for each test" in {
      app.configuration.getString("ehcacheplugin") mustBe Some("disabled")
    }
    "start the FakeApplication" in {
      Play.maybeApplication mustBe Some(app)
    }
  }
}

ScalaTest + PlayOneAppPerSuiteOneAppPerTest の両方を提供する理由は、テストの実行を最も速くさせる方法を選択できるようにするためです。もし、連続したテストの中でアプリケーションの状態を維持したい場合は OneAppPerSuite を使う必要があります。一方で、各テストでクリーンな状態が必要な場合は、OneAppPerTest または OneAppPerSuite のいずれかを使えますが、各テストの最後であらゆる状態をクリアしてください。さらに、テストスイートが最も速く実行され、複数のテストクラスが同一アプリケーションを共有する場合、OneAppPerSuite をミックスインした親のスイートと、ConfiguredApp をミックスインした入れ子のスイートを定義できます。この例については ConfiguredApp のドキュメント で参照できます。どちらの方法でも、テストスイートを最も速く実行できるほうを使用できます。

§サーバーでのテスト

時々、実際の HTTP スタックでテストをしたい時があります。もし、テストクラスのすべてのテストが同一サーバーインスタンスを再利用可能な場合、OneServerPerSuite をミックスインできます(スイート用の新規の FakeApplication も提供されます)。

class ExampleSpec extends PlaySpec with OneServerPerSuite {

  // Override app if you need a FakeApplication with other than
  // default parameters.
  implicit override lazy val app: FakeApplication =
    FakeApplication(
      additionalConfiguration = Map("ehcacheplugin" -> "disabled"),
      withRoutes = {
        case ("GET", "/") => Action { Ok("ok") }
      }
    )

  "test server logic" in {
    val myPublicAddress =  s"localhost:$port"
    val testPaymentGatewayURL = s"http://$myPublicAddress"
    // The test payment gateway requires a callback to this server before it returns a result...
    val callbackURL = s"http://$myPublicAddress/callback"
    // await is from play.api.test.FutureAwaits
    val response = await(WS.url(testPaymentGatewayURL).withQueryString("callbackURL" -> callbackURL).get())

    response.status mustBe (OK)
  }
}

もし、テストクラスのすべてのテストが独立したサーバーインスタンスを要求する場合は、代わりに OneServerPerTest を使用します(スイート用の新規の FakeApplication も提供されます)。

class ExampleSpec extends PlaySpec with OneServerPerTest {

  // Override newAppForTest if you need a FakeApplication with other than
  // default parameters.
  override def newAppForTest(testData: TestData): FakeApplication =
    new FakeApplication(
      additionalConfiguration = Map("ehcacheplugin" -> "disabled"),
      withRoutes = {
        case ("GET", "/") => Action { Ok("ok") }
      }
    )

  "The OneServerPerTest trait" must {
    "test server logic" in {
      val myPublicAddress =  s"localhost:$port"
      val testPaymentGatewayURL = s"http://$myPublicAddress"
      // The test payment gateway requires a callback to this server before it returns a result...
      val callbackURL = s"http://$myPublicAddress/callback"
      // await is from play.api.test.FutureAwaits
      val response = await(WS.url(testPaymentGatewayURL).withQueryString("callbackURL" -> callbackURL).get())

      response.status mustBe (OK)
    }
  }
}

OneServerPerSuite および OneServerPerTest トレイトは、サーバーが実行しているポート番号を port フィールドとして提供します。デフォルトは 19001 ですが、port を上書きするか、システムプロパティ testserver.port を設定することにより変更できます。継続的統合サーバーに組み入れる際に便利なので、各ビルドごとにポートを動的に予約できます。

前の例で示したように、app を上書きすることで FakeApplication をカスタマイズすることもできます。

最後に、複数のテストクラスが同一サーバーを共用できるようにすると、OneServerPerSuiteOneServerPerTest のアプローチよりも良いパフォーマンスが得られ、OneServerPerSuite をミックスインするマスタースイートと ConfiguredServer をミックインする入れ子のスイートを定義できます。ConfiguredServer のドキュメント で例で示しています。

§Web ブラウザでのテスト

ScalaTest + Play ライブラリは ScalaTest の Selenium DSL を利用して、Web ブラウザでの Play アプリケーションのテストを簡単にします。

テストクラスのすべてのテストを同一ブラウザインスタンスを使用して実行するには、テストクラスに OneBrowserPerSuite をミックスインします。また、ChromeFactoryFirefoxFactoryHtmlUnitFactoryInternetExplorerFactorySafariFactory のいずれかを Selenium Web ドライバとして提供する BrowserFactory トレイトをミックスインする必要もあります。

BrowserFactory のミックスインに加え、OneServerPerSuite
OneServerPerTestConfiguredServer のいずれかを TestServer として提供する ServerProvider トレイトをミックスインする必要もあります。

例えば、以下のテストクラスは OneServerPerSuiteHtmUnitFactory をミックスインします。

class ExampleSpec extends PlaySpec with OneServerPerSuite with OneBrowserPerSuite with HtmlUnitFactory {

  // Override app if you need a FakeApplication with other than
  // default parameters.
  implicit override lazy val app: FakeApplication =
    FakeApplication(
      additionalConfiguration = Map("ehcacheplugin" -> "disabled"),
      withRoutes = {
        case ("GET", "/testing") =>
          Action(
            Results.Ok(
              "<html>" +
                "<head><title>Test Page</title></head>" +
                "<body>" +
                "<input type='button' name='b' value='Click Me' onclick='document.title=\"scalatest\"' />" +
                "</body>" +
                "</html>"
            ).as("text/html")
          )
      }
    )

  "The OneBrowserPerTest trait" must {
    "provide a web driver" in {
      go to (s"http://localhost:$port/testing")
      pageTitle mustBe "Test Page"
      click on find(name("b")).value
      eventually { pageTitle mustBe "scalatest" }
    }
  }
}

もし、それぞれのテストが新しいブラウザインスタンスを必要とする場合、代わりに OneBrowserPerTest を使用します。OneBrowserPerSuite と同様に、ServerProviderBrowserFactory をミックスインする必要があります。

class ExampleSpec extends PlaySpec with OneServerPerTest with OneBrowserPerTest with HtmlUnitFactory {

  // Override newAppForTest if you need a FakeApplication with other than
  // default parameters.
  override def newAppForTest(testData: TestData): FakeApplication =
    new FakeApplication(
      additionalConfiguration = Map("ehcacheplugin" -> "disabled"),
      withRoutes = {
        case ("GET", "/testing") =>
          Action(
            Results.Ok(
              "<html>" +
                "<head><title>Test Page</title></head>" +
                "<body>" +
                "<input type='button' name='b' value='Click Me' onclick='document.title=\"scalatest\"' />" +
                "</body>" +
                "</html>"
            ).as("text/html")
          )
      }
    )

  "The OneBrowserPerTest trait" must {
    "provide a web driver" in {
      go to (s"http://localhost:$port/testing")
      pageTitle mustBe "Test Page"
      click on find(name("b")).value
      eventually { pageTitle mustBe "scalatest" }
    }
  }
}

もし、同一のブラウザインスタンスを共有する複数のテストクラスが必要な場合、OneBrowserPerSuite を親のスイートにミックスインし、ConfiguredBrowser を複数の入れ子スイートにミックスインします。この入れ子スイートはすべて同一の Web ブラウザを共有します。例については ConfiguredBrowser トレイトのドキュメント を参照してください。

§複数ブラウザでの同一テストの実行

もし、アプリケーションがサポートするすべてのブラウザで正しく動作することを保証するために、テストを複数の Web ブラウザで実行したい場合は、AllBrowsersPerSuite または AllBrowsersPerTest トレイトを使用できます。これらのトレイトはいずれも IndexedSeq[BrowserInfo] 型の browsers フィールドと、BrowserInfo を引数に取る abstract メソッド sharedTests を宣言します。browsers フィールドはテストを実行したいブラウザを示しています。デフォルトは、Chrome、Firefox、Internet Explorer、 HtmlUnit 、Safari です。希望するブラウザとデフォルトが異なる場合は browsers を上書きできます。複数のブラウザで実行させたいテストを sharedTests メソッドに配置し、それぞれのテスト名の末尾にブラウザの名前を記述します。(ブラウザの名前は sharedTests に渡される BrowserInfo から取得できます) AllBrowsersPerSuite を使用した例はこちらです。

class ExampleSpec extends PlaySpec with OneServerPerSuite with AllBrowsersPerSuite {

  // Override app if you need a FakeApplication with other than
  // default parameters.
  implicit override lazy val app: FakeApplication =
    FakeApplication(
      additionalConfiguration = Map("ehcacheplugin" -> "disabled"),
      withRoutes = {
        case ("GET", "/testing") =>
          Action(
            Results.Ok(
              "<html>" +
                "<head><title>Test Page</title></head>" +
                "<body>" +
                "<input type='button' name='b' value='Click Me' onclick='document.title=\"scalatest\"' />" +
                "</body>" +
                "</html>"
            ).as("text/html")
          )
      }
    )

  def sharedTests(browser: BrowserInfo) = {
    "The AllBrowsersPerSuite trait" must {
      "provide a web driver " + browser.name in {
        go to (s"http://localhost:$port/testing")
        pageTitle mustBe "Test Page"
        click on find(name("b")).value
        eventually { pageTitle mustBe "scalatest" }
      }
    }
  }
}

sharedTests によって宣言されたすべてのテストは、browsers フィールドで定義されているすべてのブラウザで、それらがホストシステムで利用できれば、実行されます。ホストシステムで利用できない、いずれのブラウザのテストも自動的にキャンセルされます。スイートの各テストが (ScalaTest によって要求された) 一意的な名前を持つように、テスト名に browser.name を手動で追加する必要があることに注意して下さい。もしこれを行わなかった場合、テストの実行時にテスト名の重複エラーが発生します。

AllBrowsersPerSuite はブラウザのタイプごとに 1 つのインスタンスを生成し、sharedTests で宣言したすべてのテストに対して使用します。もし、各テストで独自の新しいブラウザインスタンスが必要な場合は、代わりに AllBrowsersPerTest を使用してくだい。

class ExampleSpec extends PlaySpec with OneServerPerSuite with AllBrowsersPerTest {

  // Override app if you need a FakeApplication with other than
  // default parameters.
  implicit override lazy val app: FakeApplication =
    FakeApplication(
      additionalConfiguration = Map("ehcacheplugin" -> "disabled"),
      withRoutes = {
        case ("GET", "/testing") =>
          Action(
            Results.Ok(
              "<html>" +
                "<head><title>Test Page</title></head>" +
                "<body>" +
                "<input type='button' name='b' value='Click Me' onclick='document.title=\"scalatest\"' />" +
                "</body>" +
                "</html>"
            ).as("text/html")
          )
      }
    )

  def sharedTests(browser: BrowserInfo) = {
    "The AllBrowsersPerTest trait" must {
      "provide a web driver"  + browser.name in {
        go to (s"http://localhost:$port/testing")
        pageTitle mustBe "Test Page"
        click on find(name("b")).value
        eventually { pageTitle mustBe "scalatest" }
      }
    }
  }
}

AllBrowsersPerSuiteAllBrowsersPerTest は共に、利用できないブラウザタイプのテストはキャンセルしますが、テストがキャンセルされたこと自体は出力で明示されます。出力を綺麗にするために、次の例のように browsers を上書きすることにより、利用できない Web ブラウザを除外できます。

class ExampleOverrideBrowsersSpec extends PlaySpec with OneServerPerSuite with AllBrowsersPerSuite {

  override lazy val browsers =
    Vector(
      FirefoxInfo(firefoxProfile),
      ChromeInfo
    )

  // Override app if you need a FakeApplication with other than
  // default parameters.
  implicit override lazy val app: FakeApplication =
    FakeApplication(
      additionalConfiguration = Map("ehcacheplugin" -> "disabled"),
      withRoutes = {
        case ("GET", "/testing") =>
          Action(
            Results.Ok(
              "<html>" +
                "<head><title>Test Page</title></head>" +
                "<body>" +
                "<input type='button' name='b' value='Click Me' onclick='document.title=\"scalatest\"' />" +
                "</body>" +
                "</html>"
            ).as("text/html")
          )
      }
    )

  def sharedTests(browser: BrowserInfo) = {
    "The AllBrowsersPerSuite trait" must {
      "provide a web driver"  + browser.name in {
        go to (s"http://localhost:$port/testing")
        pageTitle mustBe "Test Page"
        click on find(name("b")).value
        eventually { pageTitle mustBe "scalatest" }
      }
    }
  }
}

前述のテストクラスは、Firefox と Chrome でのみ、共有されたテストの実行を試みます (そしてブラウザが利用できない場合は自動的にテストはキャンセルされます)。

§PlaySpec

PlaySpec は Play のテストでの便利な「スーパースイート」 ScalaTest ベースクラスを提供し、PlaySpec の継承によって、 WordSpecMustMatchersOptionValuesWsScalaTestClient を自動的に利用できます。

class ExampleSpec extends PlaySpec with OneServerPerSuite with  ScalaFutures with IntegrationPatience {

  // Override app if you need a FakeApplication with other than
  // default parameters.
  implicit override lazy val app: FakeApplication =
    FakeApplication(
      additionalConfiguration = Map("ehcacheplugin" -> "disabled"),
      withRoutes = {
        case ("GET", "/testing") =>
          Action(
            Results.Ok(
              "<html>" +
                "<head><title>Test Page</title></head>" +
                "<body>" +
                "<input type='button' name='b' value='Click Me' onclick='document.title=\"scalatest\"' />" +
                "</body>" +
                "</html>"
            ).as("text/html")
          )
      }
    )

  "WsScalaTestClient's" must {

    "wsUrl works correctly" in {
      val futureResult = wsUrl("/testing").get
      val body = futureResult.futureValue.body
      val expectedBody =
        "<html>" +
          "<head><title>Test Page</title></head>" +
          "<body>" +
          "<input type='button' name='b' value='Click Me' onclick='document.title=\"scalatest\"' />" +
          "</body>" +
          "</html>"
      assert(body == expectedBody)
    }

    "wsCall works correctly" in {
      val futureResult = wsCall(Call("get", "/testing")).get
      val body = futureResult.futureValue.body
      val expectedBody =
        "<html>" +
          "<head><title>Test Page</title></head>" +
          "<body>" +
          "<input type='button' name='b' value='Click Me' onclick='document.title=\"scalatest\"' />" +
          "</body>" +
          "</html>"
      assert(body == expectedBody)
    }
  }
}

前述のいずれのトレイトも PlaySpec にミックスインできます。

§異なるテストが異なるフィクスチャーを必要とする場合

前述の例で示したすべてのテストクラスにおいて、テストクラスの中のすべてもしくはほとんどのテストは同一のフィクスチャーを必要とします。これは一般的ですが、必ずしもそうではありません。同一テストクラスの中の異なるテストが異なるフィクスチャーを必要とする場合、MixedFixtures トレイトをミックスインします。そして、次のような引数なし関数のいずれかを使用して、必要なフィクスチャーを個々のテストに与えます。 AppServerChromeFirefoxHtmlUnitInternetExplorerSafari

MixedFixtures は ScalaTest の fixture.Suite を必要とし、PlaySpec は単なる標準の Suite であるため、MixedFixturesPlaySpec にミックスインできません。ミックスインされたフィクスチャー向けの便利なベースクラスが欲しい場合は、代わりに MixedPlaySpec を継承します。例はこちらです。

// MixedPlaySpec already mixes in MixedFixtures
class ExampleSpec extends MixedPlaySpec {

  // Some helper methods
  def fakeApp[A](elems: (String, String)*) = FakeApplication(additionalConfiguration = Map(elems:_*),
    withRoutes = {
      case ("GET", "/testing") =>
        Action(
          Results.Ok(
            "<html>" +
              "<head><title>Test Page</title></head>" +
              "<body>" +
              "<input type='button' name='b' value='Click Me' onclick='document.title=\"scalatest\"' />" +
              "</body>" +
              "</html>"
          ).as("text/html")
        )
    })
  def getConfig(key: String)(implicit app: Application) = app.configuration.getString(key)

  // If a test just needs a FakeApplication, use "new App":
  "The App function" must {
    "provide a FakeApplication" in new App(fakeApp("ehcacheplugin" -> "disabled")) {
      app.configuration.getString("ehcacheplugin") mustBe Some("disabled")
    }
    "make the FakeApplication available implicitly" in new App(fakeApp("ehcacheplugin" -> "disabled")) {
      getConfig("ehcacheplugin") mustBe Some("disabled")
    }
    "start the FakeApplication" in new App(fakeApp("ehcacheplugin" -> "disabled")) {
      Play.maybeApplication mustBe Some(app)
    }
  }

  // If a test needs a FakeApplication and running TestServer, use "new Server":
  "The Server function" must {
    "provide a FakeApplication" in new Server(fakeApp("ehcacheplugin" -> "disabled")) {
      app.configuration.getString("ehcacheplugin") mustBe Some("disabled")
    }
    "make the FakeApplication available implicitly" in new Server(fakeApp("ehcacheplugin" -> "disabled")) {
      getConfig("ehcacheplugin") mustBe Some("disabled")
    }
    "start the FakeApplication" in new Server(fakeApp("ehcacheplugin" -> "disabled")) {
      Play.maybeApplication mustBe Some(app)
    }
    import Helpers._
    "send 404 on a bad request" in new Server {
      import java.net._
      val url = new URL("http://localhost:" + port + "/boom")
      val con = url.openConnection().asInstanceOf[HttpURLConnection]
      try con.getResponseCode mustBe 404
      finally con.disconnect()
    }
  }

  // If a test needs a FakeApplication, running TestServer, and Selenium
  // HtmlUnit driver use "new HtmlUnit":
  "The HtmlUnit function" must {
    "provide a FakeApplication" in new HtmlUnit(fakeApp("ehcacheplugin" -> "disabled")) {
      app.configuration.getString("ehcacheplugin") mustBe Some("disabled")
    }
    "make the FakeApplication available implicitly" in new HtmlUnit(fakeApp("ehcacheplugin" -> "disabled")) {
      getConfig("ehcacheplugin") mustBe Some("disabled")
    }
    "start the FakeApplication" in new HtmlUnit(fakeApp("ehcacheplugin" -> "disabled")) {
      Play.maybeApplication mustBe Some(app)
    }
    import Helpers._
    "send 404 on a bad request" in new HtmlUnit {
      import java.net._
      val url = new URL("http://localhost:" + port + "/boom")
      val con = url.openConnection().asInstanceOf[HttpURLConnection]
      try con.getResponseCode mustBe 404
      finally con.disconnect()
    }
    "provide a web driver" in new HtmlUnit(fakeApp()) {
      go to ("http://localhost:" + port + "/testing")
      pageTitle mustBe "Test Page"
      click on find(name("b")).value
      eventually { pageTitle mustBe "scalatest" }
    }
  }

  // If a test needs a FakeApplication, running TestServer, and Selenium
  // Firefox driver use "new Firefox":
  "The Firefox function" must {
    "provide a FakeApplication" in new Firefox(fakeApp("ehcacheplugin" -> "disabled")) {
      app.configuration.getString("ehcacheplugin") mustBe Some("disabled")
    }
    "make the FakeApplication available implicitly" in new Firefox(fakeApp("ehcacheplugin" -> "disabled")) {
      getConfig("ehcacheplugin") mustBe Some("disabled")
    }
    "start the FakeApplication" in new Firefox(fakeApp("ehcacheplugin" -> "disabled")) {
      Play.maybeApplication mustBe Some(app)
    }
    import Helpers._
    "send 404 on a bad request" in new Firefox {
      import java.net._
      val url = new URL("http://localhost:" + port + "/boom")
      val con = url.openConnection().asInstanceOf[HttpURLConnection]
      try con.getResponseCode mustBe 404
      finally con.disconnect()
    }
    "provide a web driver" in new Firefox(fakeApp()) {
      go to ("http://localhost:" + port + "/testing")
      pageTitle mustBe "Test Page"
      click on find(name("b")).value
      eventually { pageTitle mustBe "scalatest" }
    }
  }

  // If a test needs a FakeApplication, running TestServer, and Selenium
  // Safari driver use "new Safari":
  "The Safari function" must {
    "provide a FakeApplication" in new Safari(fakeApp("ehcacheplugin" -> "disabled")) {
      app.configuration.getString("ehcacheplugin") mustBe Some("disabled")
    }
    "make the FakeApplication available implicitly" in new Safari(fakeApp("ehcacheplugin" -> "disabled")) {
      getConfig("ehcacheplugin") mustBe Some("disabled")
    }
    "start the FakeApplication" in new Safari(fakeApp("ehcacheplugin" -> "disabled")) {
      Play.maybeApplication mustBe Some(app)
    }
    import Helpers._
    "send 404 on a bad request" in new Safari {
      import java.net._
      val url = new URL("http://localhost:" + port + "/boom")
      val con = url.openConnection().asInstanceOf[HttpURLConnection]
      try con.getResponseCode mustBe 404
      finally con.disconnect()
    }
    "provide a web driver" in new Safari(fakeApp()) {
      go to ("http://localhost:" + port + "/testing")
      pageTitle mustBe "Test Page"
      click on find(name("b")).value
      eventually { pageTitle mustBe "scalatest" }
    }
  }

  // If a test needs a FakeApplication, running TestServer, and Selenium
  // Chrome driver use "new Chrome":
  "The Chrome function" must {
    "provide a FakeApplication" in new Chrome(fakeApp("ehcacheplugin" -> "disabled")) {
      app.configuration.getString("ehcacheplugin") mustBe Some("disabled")
    }
    "make the FakeApplication available implicitly" in new Chrome(fakeApp("ehcacheplugin" -> "disabled")) {
      getConfig("ehcacheplugin") mustBe Some("disabled")
    }
    "start the FakeApplication" in new Chrome(fakeApp("ehcacheplugin" -> "disabled")) {
      Play.maybeApplication mustBe Some(app)
    }
    import Helpers._
    "send 404 on a bad request" in new Chrome {
      import java.net._
      val url = new URL("http://localhost:" + port + "/boom")
      val con = url.openConnection().asInstanceOf[HttpURLConnection]
      try con.getResponseCode mustBe 404
      finally con.disconnect()
    }
    "provide a web driver" in new Chrome(fakeApp()) {
      go to ("http://localhost:" + port + "/testing")
      pageTitle mustBe "Test Page"
      click on find(name("b")).value
      eventually { pageTitle mustBe "scalatest" }
    }
  }

  // If a test needs a FakeApplication, running TestServer, and Selenium
  // InternetExplorer driver use "new InternetExplorer":
  "The InternetExplorer function" must {
    "provide a FakeApplication" in new InternetExplorer(fakeApp("ehcacheplugin" -> "disabled")) {
      app.configuration.getString("ehcacheplugin") mustBe Some("disabled")
    }
    "make the FakeApplication available implicitly" in new InternetExplorer(fakeApp("ehcacheplugin" -> "disabled")) {
      getConfig("ehcacheplugin") mustBe Some("disabled")
    }
    "start the FakeApplication" in new InternetExplorer(fakeApp("ehcacheplugin" -> "disabled")) {
      Play.maybeApplication mustBe Some(app)
    }
    import Helpers._
    "send 404 on a bad request" in new InternetExplorer {
      import java.net._
      val url = new URL("http://localhost:" + port + "/boom")
      val con = url.openConnection().asInstanceOf[HttpURLConnection]
      try con.getResponseCode mustBe 404
      finally con.disconnect()
    }
    "provide a web driver" in new InternetExplorer(fakeApp()) {
      go to ("http://localhost:" + port + "/testing")
      pageTitle mustBe "Test Page"
      click on find(name("b")).value
      eventually { pageTitle mustBe "scalatest" }
    }
  }

  // If a test does not need any special fixtures, just 
  // write "in { () => ..."
  "Any old thing" must {
    "be doable without much boilerplate" in { () =>
       1 + 1 mustEqual 2
     }
  }
}

§テンプレートのテスト

テンプレートは標準的な Scala の機能なので、テストから実行でき、そして結果を確認できます。

"render index template" in new App {
  val html = views.html.index("Coco")

  contentAsString(html) must include ("Hello Coco")
}

§コントローラーのテスト

FakeRequest の提供による、いずれの Action コードも呼び出すことができます。

import scala.concurrent.Future

import org.scalatest._
import org.scalatestplus.play._

import play.api.mvc._
import play.api.test._
import play.api.test.Helpers._

class ExampleControllerSpec extends PlaySpec with Results {

  class TestController() extends Controller with ExampleController

  "Example Page#index" should {
    "should be valid" in {
      val controller = new TestController()
      val result: Future[Result] = controller.index().apply(FakeRequest())
      val bodyText: String = contentAsString(result)
      bodyText mustBe "ok"
    }
  }
}

技術的に、ここで WithApplication は不要ですが、それにより何かを損なうことはありません。

§ルーターのテスト

自分で Action を呼び出す代わりに、Router にそれをさせることができます。

"respond to the index Action" in new App(fakeApplication) {
  val Some(result) = route(FakeRequest(GET, "/Bob"))

  status(result) mustEqual OK
  contentType(result) mustEqual Some("text/html")
  charset(result) mustEqual Some("utf-8")
  contentAsString(result) must include ("Hello Bob")
}

§モデルのテスト

SQL データベースを使用する時、inMemoryDatabase を使用して H2 データベースのインメモリインスタンスでデータベース接続を置き換えることができます。

val appWithMemoryDatabase = FakeApplication(additionalConfiguration = inMemoryDatabase("test"))
"run an application" in new App(appWithMemoryDatabase) {

  val Some(macintosh) = Computer.findById(21)

  macintosh.name mustEqual "Macintosh"
  macintosh.introduced.value mustEqual "1984-01-24"
}

§WS 呼び出しのテスト

Web サービスの呼び出しを行う時、WSTestClient を使用することができます。wsCallwsUrl の 2 つの呼び出しが可能で、それぞれ Call または文字列を引数に取ります。WithApplication のコンテキスト内での呼び出しが期待されていることに注意してください。

wsCall(controllers.routes.Application.index()).get()
wsUrl("http://localhost:9000").get()

Next: Specs2 によるテスト


このドキュメントの翻訳は Play チームによってメンテナンスされているものではありません。 間違いを見つけた場合、このページのソースコードを ここ で確認することができます。 ドキュメントガイドライン を読んで、お気軽にプルリクエストを送ってください。