ドキュメント

§ScalaTest を使用した機能テストの記述

Play は、機能テストを支援する多くのクラスと便利なメソッドを提供しています。これらのほとんどは、play.api.test パッケージ内、または Helpers オブジェクト内にあります。ScalaTest + Play 統合ライブラリは、ScalaTest のこのテストサポートを基に構築されています。

次のインポートを使用すると、Play の組み込みテストサポートと ScalaTest + Play のすべてにアクセスできます。

import org.scalatest._
import org.scalatest.matchers.must.Matchers
import org.scalatest.wordspec.FixtureAnyWordSpec
import org.scalatestplus.play._
import play.api.http.MimeTypes
import play.api.test._
import play.api.test.Helpers._

§テスト用の Application インスタンスの作成

Play では、コンテキストとして実行中の Application が頻繁に必要になります。テスト環境にアプリケーションを提供する方法は、アプリケーションの構築方法によって異なります。デフォルトの Guice 依存性注入を使用している場合は、GuiceApplicationBuilder クラスを使用できます。このクラスは、異なる構成、ルート、または追加モジュールで構成できます。

val application: Application = new GuiceApplicationBuilder()
  .configure("some.configuration" -> "value")
  .build()

GuiceApplicationBuilder を明示的に使用してアプリケーションを作成するのではなく、GuiceFakeApplicationFactory トレイトをミックスインすることで、デフォルトのアプリケーションを作成できます。

テストクラス内のすべてのテストまたはほとんどのテストで Application が必要で、それらすべてが同じ Application インスタンスを共有できる場合は、GuiceFakeApplicationFactory トレイトとともに GuiceOneAppPerSuite トレイトをミックスインします。app フィールドから Application にアクセスできます。

Application をカスタマイズする必要がある場合は、この例に示すように fakeApplication() をオーバーライドします。

class ExampleSpec extends PlaySpec with GuiceOneAppPerSuite {

  // Override fakeApplication if you need a Application with other than
  // default parameters.
  override def fakeApplication(): Application = {
    GuiceApplicationBuilder().configure(Map("ehcacheplugin" -> "disabled")).build()
  }

  "The GuiceOneAppPerSuite trait" must {
    "provide an Application" in {
      app.configuration.getOptional[String]("ehcacheplugin") mustBe Some("disabled")
    }
  }
}

GuiceFakeApplicationFactory を手動でミックスインしたくない場合は、GuiceOneAppPerSuite を使用することもできます。

各テストで同じものを共有するのではなく、独自の Application を取得する必要がある場合は、代わりに OneAppPerTest または GuiceOneAppPerTest を使用します。

class ExampleSpec extends PlaySpec with GuiceOneAppPerTest {

  // Override newAppForTest if you need an Application with other than
  // default parameters.
  override def newAppForTest(td: TestData): Application = {
    GuiceApplicationBuilder().configure(Map("ehcacheplugin" -> "disabled")).build()
  }

  "The OneAppPerTest trait" must {
    "provide a new Application for each test" in {
      app.configuration.getOptional[String]("ehcacheplugin") mustBe Some("disabled")
    }
  }
}

ScalaTest + PlayGuiceOneAppPerSuiteOneAppPerTest の両方を提供している理由は、テストを最速で実行できる共有戦略を選択できるようにするためです。連続するテスト間でアプリケーションの状態を維持したい場合は、GuiceOneAppPerSuite を使用する必要があります。ただし、各テストにクリーンな状態が必要な場合は、OneAppPerTest を使用するか、GuiceOneAppPerSuite を使用して各テストの最後に状態をクリアできます。さらに、複数のテストクラスが同じアプリケーションを共有する場合にテストスイートの実行速度が最速になる場合は、GuiceOneAppPerSuite をミックスインするマスタースイートと、ConfiguredApp をミックスインするネストされたスイートを定義できます。ConfiguredApp のドキュメント の例で示されています。テストスイートの実行速度を最も速くする戦略を使用できます。

§サーバーを使用したテスト

実際の HTTP スタックでテストしたい場合があります。テストクラス内のすべてのテストで同じサーバーインスタンスを再利用できる場合は、OneServerPerSuite をミックスインできます(スイートの新しい Application も提供します)。

class ExampleSpec extends PlaySpec with GuiceOneServerPerSuite {

  // Override app if you need an Application with other than
  // default parameters.
  override def fakeApplication(): Application = {
    GuiceApplicationBuilder()
      .appRoutes(app => {
        case ("GET", "/") => app.injector.instanceOf(classOf[DefaultActionBuilder]) { Ok("ok") }
      })
      .build()
  }

  "test server logic" in {
    val wsClient              = app.injector.instanceOf[WSClient]
    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(wsClient.url(testPaymentGatewayURL).addQueryStringParameters("callbackURL" -> callbackURL).get())

    response.status mustBe OK
  }
}

テストクラス内のすべてのテストで個別のサーバーインスタンスが必要な場合は、代わりに OneServerPerTest を使用します(スイートの新しい Application も提供します)。

class ExampleSpec extends PlaySpec with GuiceOneServerPerTest {

  // Override newAppForTest or mixin GuiceFakeApplicationFactory and use fakeApplication() for an Application
  override def newAppForTest(testData: TestData): Application = {
    GuiceApplicationBuilder()
      .appRoutes(app => {
        case ("GET", "/") =>
          app.injector.instanceOf(classOf[DefaultActionBuilder]) {
            Ok("ok")
          }
      })
      .build()
  }

  "The OneServerPerTest trait" must {
    "test server logic" in {
      val wsClient              = app.injector.instanceOf[WSClient]
      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(wsClient.url(testPaymentGatewayURL).addQueryStringParameters("callbackURL" -> callbackURL).get())

      response.status mustBe OK
    }
  }
}

OneServerPerSuite および OneServerPerTest トレイトは、サーバーが実行されているポート番号を port フィールドとして提供します。デフォルトでは、これはランダムポートですが、port をオーバーライドするか、システムプロパティ testserver.port を設定することで変更できます。これは、継続的インテグレーションサーバーと統合する場合に便利です。これにより、各ビルドに対してポートを動的に予約できます。

前の例で示したように、app をオーバーライドして Application をカスタマイズすることもできます。

最後に、複数のテストクラスが同じサーバーを共有することで、OneServerPerSuite または OneServerPerTest のいずれのアプローチよりもパフォーマンスが向上する場合は、OneServerPerSuite をミックスインするマスタースイートと、ConfiguredServer をミックスインするネストされたスイートを定義できます。ConfiguredServer のドキュメント の例で示されています。

§Web ブラウザーを使用したテスト

ScalaTest + Play ライブラリは、ScalaTest の Selenium DSL を基に構築されており、Web ブラウザーから Play アプリケーションを簡単にテストできるようにします。

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

BrowserFactory のミックスインに加えて、TestServer を提供する ServerProvider トレイトもミックスインする必要があります。OneServerPerSuiteOneServerPerTest、または ConfiguredServer のいずれかです。

たとえば、次のテストクラスは OneServerPerSuiteHtmUnitFactory をミックスインします。

class ExampleSpec extends PlaySpec with GuiceOneServerPerSuite with OneBrowserPerSuite with HtmlUnitFactory {

  // Override app if you need an Application with other than
  // default parameters.
  override def fakeApplication(): Application = {
    import play.api.http.MimeTypes._
    import play.api.mvc.Results._

    GuiceApplicationBuilder()
      .appRoutes(app => {
        case ("GET", "/testing") =>
          app.injector.instanceOf(classOf[DefaultActionBuilder]) {
            Ok("""
                 |<html>
                 | <head>
                 |   <title>Test Page</title>
                 |   <body>
                 |     <input type='button' name='b' value='Click Me' onclick='document.title="scalatest"' />
                 |   </body>
                 | </head>
                 |</html>
            """.stripMargin).as(HTML)
          }
      })
      .build()
  }

  "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 GuiceOneServerPerTest with OneBrowserPerTest with HtmlUnitFactory {

  // Override app if you need an Application with other than
  // default parameters.
  override def newAppForTest(testData: TestData): Application = {
    import play.api.http.MimeTypes._
    import play.api.mvc.Results._

    GuiceApplicationBuilder()
      .appRoutes(app => {
        case ("GET", "/testing") =>
          app.injector.instanceOf(classOf[DefaultActionBuilder]) {
            Ok("""
                 |<html>
                 | <head>
                 |   <title>Test Page</title>
                 |   <body>
                 |     <input type='button' name='b' value='Click Me' onclick='document.title="scalatest"' />
                 |   </body>
                 | </head>
                 |</html>
            """.stripMargin).as(HTML)
          }
      })
      .build()
  }

  "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を引数に取る抽象メソッドsharedTestsを宣言します。browsersフィールドは、テストを実行したいブラウザを示します。デフォルトは、Chrome、Firefox、Internet Explorer、HtmlUnit、およびSafariです。デフォルトがニーズに合わない場合は、browsersをオーバーライドできます。複数のブラウザで実行したいテストをsharedTestsメソッドに配置し、各テスト名の最後にブラウザ名を付けます。(ブラウザ名は、sharedTestsに渡されるBrowserInfoから取得できます。)以下に、AllBrowsersPerSuiteを使用する例を示します。

class ExampleSpec extends PlaySpec with GuiceOneServerPerSuite with AllBrowsersPerSuite {

  // Override app if you need an Application with other than
  // default parameters.
  override def fakeApplication(): Application = {
    import play.api.http.MimeTypes._
    import play.api.mvc.Results._

    GuiceApplicationBuilder()
      .appRoutes(app => {
        case ("GET", "/testing") =>
          app.injector.instanceOf(classOf[DefaultActionBuilder]) {
            Ok("""
                 |<html>
                 | <head>
                 |   <title>Test Page</title>
                 |   <body>
                 |     <input type='button' name='b' value='Click Me' onclick='document.title="scalatest"' />
                 |   </body>
                 | </head>
                 |</html>
            """.stripMargin).as(HTML)
          }
      })
      .build()
  }

  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は、各ブラウザタイプの単一のインスタンスを作成し、sharedTestsで宣言されたすべてのテストに使用します。各テストに独自の新しいブラウザインスタンスが必要な場合は、代わりにAllBrowsersPerTestを使用します。

class ExampleSpec extends PlaySpec with GuiceOneServerPerSuite with AllBrowsersPerTest {

  // Override app if you need an Application with other than
  // default parameters.
  override def fakeApplication(): Application = {
    import play.api.http.MimeTypes._
    import play.api.mvc.Results._

    GuiceApplicationBuilder()
      .appRoutes(app => {
        case ("GET", "/testing") =>
          app.injector.instanceOf(classOf[DefaultActionBuilder]) {
            Ok("""
                 |<html>
                 | <head>
                 |   <title>Test Page</title>
                 |   <body>
                 |     <input type='button' name='b' value='Click Me' onclick='document.title="scalatest"' />
                 |   </body>
                 | </head>
                 |</html>
            """.stripMargin).as(HTML)
          }
      })
      .build()
  }

  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 GuiceOneServerPerSuite with AllBrowsersPerSuite {

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

  // Override app if you need an Application with other than
  // default parameters.
  override def fakeApplication(): Application = {
    import play.api.http.MimeTypes._
    import play.api.mvc.Results._

    GuiceApplicationBuilder()
      .appRoutes(app => {
        case ("GET", "/testing") =>
          app.injector.instanceOf(classOf[DefaultActionBuilder]) {
            Ok("""
                 |<html>
                 | <head>
                 |   <title>Test Page</title>
                 |   <body>
                 |     <input type='button' name='b' value='Click Me' onclick='document.title="scalatest"' />
                 |   </body>
                 | </head>
                 |</html>
            """.stripMargin).as(HTML)
          }
      })
      .build()
  }

  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を拡張することにより、WordSpecMustMatchersOptionValues、およびWsScalaTestClientが自動的に取得されます。

class ExampleSpec extends PlaySpec with GuiceOneServerPerSuite with ScalaFutures with IntegrationPatience {

  // Override app if you need an Application with other than
  // default parameters.
  override def fakeApplication(): Application = {

    import play.api.http.MimeTypes._
    import play.api.mvc.Results._

    GuiceApplicationBuilder()
      .appRoutes(app => {
        case ("GET", "/testing") =>
          app.injector.instanceOf(classOf[DefaultActionBuilder]) {
            Ok("""
                 |<html>
                 | <head>
                 |   <title>Test Page</title>
                 |   <body>
                 |     <input type='button' name='b' value='Click Me' onclick='document.title="scalatest"' />
                 |   </body>
                 | </head>
                 |</html>""".stripMargin).as(HTML)
          }
      })
      .build()
  }

  "WsScalaTestClient's" must {

    "wsUrl works correctly" in {
      implicit val ws: WSClient = app.injector.instanceOf(classOf[WSClient])
      val futureResult          = wsUrl("/testing").get()
      val body                  = futureResult.futureValue.body
      val expectedBody =
        """
          |<html>
          | <head>
          |   <title>Test Page</title>
          |   <body>
          |     <input type='button' name='b' value='Click Me' onclick='document.title="scalatest"' />
          |   </body>
          | </head>
          |</html>""".stripMargin
      assert(body == expectedBody)
    }

    "wsCall works correctly" in {
      implicit val ws: WSClient = app.injector.instanceOf(classOf[WSClient])
      val futureResult          = wsCall(Call("get", "/testing")).get()
      val body                  = futureResult.futureValue.body
      val expectedBody =
        """
          |<html>
          | <head>
          |   <title>Test Page</title>
          |   <body>
          |     <input type='button' name='b' value='Click Me' onclick='document.title="scalatest"' />
          |   </body>
          | </head>
          |</html>""".stripMargin
      assert(body == expectedBody)
    }
  }
}

前述のトレイトをPlaySpecにミックスインできます。

§異なるテストに異なるフィクスチャが必要な場合

前の例に示したすべてのテストクラスでは、テストクラス内のすべてのテストまたはほとんどのテストで同じフィクスチャが必要でした。これは一般的ですが、常にそうであるとは限りません。同じテストクラス内の異なるテストに異なるフィクスチャが必要な場合は、トレイトMixedFixturesをミックスインします。次に、次の引数なし関数を使用して、各個々のテストに必要なフィクスチャを提供します:AppServerChromeFirefoxHtmlUnitInternetExplorer、またはSafari

MixedFixturesは、ScalaTestのfixture.Suiteを必要とするため、PlaySpecにミックスインできません。また、PlaySpecは通常のSuiteにすぎません。混合フィクスチャの便利なベースクラスが必要な場合は、代わりにMixedPlaySpecを拡張します。以下に例を示します。

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

  // Some helper methods
  def buildApp[A](elems: (String, String)*): Application = {
    import play.api.http.MimeTypes._
    import play.api.mvc.Results._

    GuiceApplicationBuilder()
      .appRoutes(app => {
        case ("GET", "/testing") =>
          app.injector.instanceOf(classOf[DefaultActionBuilder]) {
            Ok("""
                 |<html>
                 | <head>
                 |   <title>Test Page</title>
                 |   <body>
                 |     <input type='button' name='b' value='Click Me' onclick='document.title="scalatest"' />
                 |   </body>
                 | </head>
                 |</html>
            """.stripMargin).as(HTML)
          }
      })
      .configure(Map(elems: _*))
      .build()
  }

  def getConfig(key: String)(implicit app: Application): Option[String] = app.configuration.getOptional[String](key)

  // If a test just needs an Application, use "new App":
  "The App function" must {
    "provide an Application" in new App(buildApp("ehcacheplugin" -> "disabled")) {
      override def running() = app.configuration.getOptional[String]("ehcacheplugin") mustBe Some("disabled")
    }
    "make the Application available implicitly" in new App(buildApp("ehcacheplugin" -> "disabled")) {
      override def running() = getConfig("ehcacheplugin") mustBe Some("disabled")
    }
  }

  // If a test needs an Application and running TestServer, use "new Server":
  "The Server function" must {
    "provide an Application" in new Server(buildApp("ehcacheplugin" -> "disabled")) {
      override def running() = app.configuration.getOptional[String]("ehcacheplugin") mustBe Some("disabled")
    }
    "make the Application available implicitly" in new Server(buildApp("ehcacheplugin" -> "disabled")) {
      override def running() = getConfig("ehcacheplugin") mustBe Some("disabled")
    }
    "send 404 on a bad request" in new Server {
      override def running() = {
        import java.net._
        val url                    = new URI("http://localhost:" + port + "/boom").toURL
        val con: HttpURLConnection = url.openConnection().asInstanceOf[HttpURLConnection]
        try con.getResponseCode mustBe 404
        finally con.disconnect()
      }
    }
  }

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

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

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

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

  // If a test needs an Application, running TestServer, and Selenium
  // InternetExplorer driver use "new InternetExplorer":
  "The InternetExplorer function" must {
    "provide an Application" in new InternetExplorer(buildApp("ehcacheplugin" -> "disabled")) {
      override def running() = app.configuration.getOptional[String]("ehcacheplugin") mustBe Some("disabled")
    }
    "make the Application available implicitly" in new InternetExplorer(buildApp("ehcacheplugin" -> "disabled")) {
      override def running() = getConfig("ehcacheplugin") mustBe Some("disabled")
    }
    "send 404 on a bad request" in new InternetExplorer {
      override def running() = {
        import java.net._
        val url                    = new URI("http://localhost:" + port + "/boom").toURL
        val con: HttpURLConnection = url.openConnection().asInstanceOf[HttpURLConnection]
        try con.getResponseCode mustBe 404
        finally con.disconnect()
      }
    }
    "provide a web driver" in new InternetExplorer(buildApp()) {
      override def running() = {
        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 {
  override def running() = {
    val html = views.html.index("Coco")

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

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

FakeRequestを提供することで、任意のActionコードを呼び出すことができます。

import scala.concurrent.Future

import org.scalatestplus.play._

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

class ExampleControllerSpec extends PlaySpec with Results {

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

§ルーターのテスト

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

"respond to the index Action" in new App(applicationWithRouter) {
  override def running() = {
    val Some(result) = route(app, FakeRequest(GET_REQUEST, "/Bob"))

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

§モデルのテスト

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

val appWithMemoryDatabase = new GuiceApplicationBuilder().configure(inMemoryDatabase("test")).build()
"run an application" in new App(appWithMemoryDatabase) {

  override def running() = {
    val Some(macintosh) = Computer.findById(21)

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

§WSコールのテスト

Webサービスを呼び出している場合は、WSTestClientを使用できます。wsCallwsUrlの2つの呼び出しがあり、それぞれCallまたは文字列を受け取ります。実行中のアプリケーションのコンテキストで呼び出される必要があることに注意してください。

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

次へ:specs2でのテスト


このドキュメントにエラーがありましたか?このページのソースコードはこちらにあります。ドキュメントのガイドラインを読んだ後、プルリクエストを自由にご投稿ください。質問や共有するアドバイスがありますか?コミュニティフォーラムにアクセスして、コミュニティとの会話を始めましょう。