How to start Play application before tests and the

2019-03-30 14:54发布

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)

2条回答
forever°为你锁心
2楼-- · 2019-03-30 14:56

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())

}
查看更多
劳资没心,怎么记你
3楼-- · 2019-03-30 15:16

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.

查看更多
登录 后发表回答