问题
My goal is to get an application running and execute multiple tests on the same instance of the app.
I have tried this solution without much luck. Here is my test:
class ApplicationSpec extends Specification { sequential
object AppWithTestDb2 extends FakeApplication(additionalConfiguration =
Map(
("db.default.driver") -> "org.h2.Driver",
("db.default.url") -> (
// "jdbc:h2:mem:play-test-" + scala.util.Random.nextInt + // in memory database
"jdbc:h2:/tmp/play-test-" + scala.util.Random.nextInt + // file based db that can be accessed using h2-browse in activator
";MODE=PostgreSQL;DATABASE_TO_UPPER=false;DB_CLOSE_DELAY=-1")
))
running(AppWithTestDb2) {
"Application" should {
"send 404 on a bad request" in {
route(FakeRequest(GET, "/boum")) must beNone
}
"post signup request" in {
val res = route(FakeRequest(POST, "/user", FakeHeaders(), TestData.newUser)).get
status(res) must equalTo(OK)
contentType(res) must beSome("application/json")
contentAsJson(res) mustEqual TestData.newUser
}
"fail signup request for existing user" in {
val res1 = route(FakeRequest(POST, "/user", FakeHeaders(), TestData.newUser)).get
Await.result(res1, Duration.Inf)
val res = route(FakeRequest(POST, "/user", FakeHeaders(), TestData.newUser)).get
Await.result(res, Duration.Inf)
status(res) must equalTo(CONFLICT)
contentType(res) must beSome("application/json")
contentAsJson(res) mustEqual TestData.newUser
}
}
}
}
The problem here is that application starts and stops immediately and tests are executed without a running application:
[debug] c.j.b.BoneCPDataSource - JDBC URL = jdbc:h2:/tmp/play-test--437407884;MODE=PostgreSQL;DATABASE_TO_UPPER=false;DB_CLOSE_DELAY=-1, Username = zalando, partitions = 1, max (per partition) = 30, min (per partition) = 5, idle max age = 10 min, idle test period = 1 min, strategy = DEFAULT
[info] application - Application has started
[debug] application - Binding to Slick DAO implementations.
[info] application - Application shutdown...
[debug] c.j.b.BoneCPDataSource - Connection pool has been shut down
[info] ApplicationSpec
[info]
[info] Application should
[info] ! send 404 on a bad request
[error] RuntimeException: : There is no started application (Play.scala:71)
[error] play.api.Play$$anonfun$current$1.apply(Play.scala:71)
[error] play.api.Play$$anonfun$current$1.apply(Play.scala:71)
[error] play.api.Play$.current(Play.scala:71)
[error] play.api.test.RouteInvokers$class.route(Helpers.scala:305)
[error] play.api.test.Helpers$.route(Helpers.scala:403)
[error] ApplicationSpec$$anonfun$1$$anonfun$apply$7$$anonfun$apply$8$$anonfun$apply$9.apply(ApplicationSpec.scala:76)
[error] ApplicationSpec$$anonfun$1$$anonfun$apply$7$$anonfun$apply$8$$anonfun$apply$9.apply(ApplicationSpec.scala:76)
[error] ApplicationSpec$$anonfun$1$$anonfun$apply$7$$anonfun$apply$8.apply(ApplicationSpec.scala:76)
[error] ApplicationSpec$$anonfun$1$$anonfun$apply$7$$anonfun$apply$8.apply(ApplicationSpec.scala:76)
回答1:
In specs2 there is a distinction between test declaration and test execution. When you write "application" should ...
you just declare tests. The executable part is what is enclosed in the ... in ...
part.
So when you declare running(AppWithTestDb2) { ... }
you just create some tests inside the context of an AppTestDb2
application.
The general solution for what you want to achieve in specs2 is to use Steps
like this:
class ApplicationSpec extends Specification { sequential
step("start application")
"Application" should {
"send 404 on a bad request" in { ... }
"post signup request" in { ... }
}
step("stop application")
}
Then, the way the specs2 execution model works, you will get your fake application started before all the tests start and terminated when all the tests are finished (whether you use sequential
or not)
I am not a Play user but I suspect that you should be able to reuse the WithApplication class or something similar to create your start/stop steps. Otherwise there is a blog post here exploring a solution for the same problem.
回答2:
Here is my working solution
object AppWithTestDb2 extends FakeApplication(additionalConfiguration =
Map(
("db.default.driver") -> "org.h2.Driver",
("db.default.url") -> (
// "jdbc:h2:mem:play-test-" + scala.util.Random.nextInt + // in memory database
"jdbc:h2:/tmp/play-test-" + scala.util.Random.nextInt + // file based db that can be accessed using h2-browse in activator
";MODE=PostgreSQL;DATABASE_TO_UPPER=false;DB_CLOSE_DELAY=-1")
))
class SignupLoginSpec extends Specification { sequential
step(Play.start(AppWithTestDb2))
"application" should {
"post signup request" in {
val res = route(FakeRequest(POST, "/user", FakeHeaders(), TestData.newUser)).get
status(res) must equalTo(OK)
contentType(res) must beSome("application/json")
contentAsJson(res) mustEqual TestData.newUser
}
"fail signup request for existing user" in {
val res1 = route(FakeRequest(POST, "/user", FakeHeaders(), TestData.newUser)).get
Await.result(res1, Duration.Inf)
val res = route(FakeRequest(POST, "/user", FakeHeaders(), TestData.newUser)).get
Await.result(res, Duration.Inf)
status(res) must equalTo(CONFLICT)
contentType(res) must beSome("application/json")
contentAsJson(res) mustEqual TestData.newUser
}
}
step(Play.stop())
}
来源:https://stackoverflow.com/questions/27567512/how-to-start-play-application-before-tests-and-then-shut-it-down-in-specs2