§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 + Play が GuiceOneAppPerSuite
と OneAppPerTest
の両方を提供している理由は、テストを最速で実行できる共有戦略を選択できるようにするためです。連続するテスト間でアプリケーションの状態を維持したい場合は、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
トレイトもミックスインする必要があります。ChromeFactory
、FirefoxFactory
、HtmlUnitFactory
、InternetExplorerFactory
、SafariFactory
のいずれかです。
BrowserFactory
のミックスインに加えて、TestServer
を提供する ServerProvider
トレイトもミックスインする必要があります。OneServerPerSuite
、OneServerPerTest
、または ConfiguredServer
のいずれかです。
たとえば、次のテストクラスは OneServerPerSuite
と HtmUnitFactory
をミックスインします。
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
と同様に、ServerProvider
と BrowserFactory
もミックスインする必要があります。
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" }
}
}
}
}
AllBrowsersPerSuite
とAllBrowsersPerTest
の両方が利用できないブラウザタイプのテストをキャンセルしますが、テストは出力でキャンセル済みとして表示されます。出力をクリーンアップするために、次の例に示すように、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
を拡張することにより、WordSpec
、MustMatchers
、OptionValues
、および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
をミックスインします。次に、次の引数なし関数を使用して、各個々のテストに必要なフィクスチャを提供します:App、Server、Chrome、Firefox、HtmlUnit、InternetExplorer、または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
を使用できます。wsCall
とwsUrl
の2つの呼び出しがあり、それぞれCallまたは文字列を受け取ります。実行中のアプリケーションのコンテキストで呼び出される必要があることに注意してください。
wsCall(controllers.routes.Application.index()).get()
wsUrl("http://localhost:9000").get()
次へ:specs2でのテスト
このドキュメントにエラーがありましたか?このページのソースコードはこちらにあります。ドキュメントのガイドラインを読んだ後、プルリクエストを自由にご投稿ください。質問や共有するアドバイスがありますか?コミュニティフォーラムにアクセスして、コミュニティとの会話を始めましょう。