Quick test execution in a fake playframework application

Running the tests described here

"Spec" should { "example" in new WithApplication { ... } } 

unacceptably slower for me. This is because the new WithApplication method starts and stops the structure in each example. Do not get me wrong, the platform itself loads very quickly, but if the database is configured (surprise!), The situation becomes terrible.

Here are some measurements:

 "The database layer" should { "test1" in { 1 must be equalTo(1) } ... "test20" in { 1 must be equalTo(1) } } 

Runtime: 2 seconds . The same test with WithApplication in each example takes 9 seconds.

I was able to achieve much better results thanks to this answer.

 import play.api.Play import play.api.test.FakeApplication import org.specs2.mutable.Specification import scalikejdbc._ class MySpec extends Specification { var fake: FakeApplication = _ step {fake = FakeApplication(...)} step {Play.start(fake)} "The database layer" should { "some db test" in { DB localTx { implicit session => ... } } "another db test" in { DB localTx { implicit session => ... } } step {Play.stop()} } 

}

Pros: increased productivity

Minuses:

  • you need to copy-paste the settings and disrupt the code, because you don’t know how to reuse (reuse I mean something like "class MySpec extends Specification with NoWasteOfTime "

  • new WithApplication () calls Helpers.running, which looks like this

 synchronized { try { Play.start(fakeApp) block } finally { Play.stop() play.api.libs.ws.WS.resetClient() } } 

therefore, I cannot fully emulate the behavior of Helpers.running (resetClient is not displayed for my code) without reflection.

Please suggest how to break down the cons or another approach, how to solve my problem.

+8
scala playframework specs2
source share
1 answer

I do not know if this is the best solution, but in this thread: Execute code before and after specification

You can read the solution for reusable code. I implemented it with a few changes. For me, the beforeAll step did not start and added the sequential modifier.

 import org.specs2.mutable._ import org.specs2.specification._ class PlayAppSpec extends Specification with BeforeAllAfterAll{ sequential lazy val app : FakeApplication = { FakeApplication() } def beforeAll(){ Play.start(app) } def afterAll(){ Play.stop() } } import org.specs2.specification.Step trait BeforeAllAfterAll extends Specification { // see http://bit.ly/11I9kFM (specs2 User Guide) override def map(fragments: =>Fragments) = { beforeAll() fragments ^ Step(afterAll) } def beforeAll() def afterAll() } 

I think map will be better with Step(...) ^ fragments ^ Step(...) , but it did not run beforeAll for me. The user manual ( http://bit.ly/11I9kFM ) in the Global Setup / Disable section says that lazy val is used.

All in all, it hurt to set it up. My problem was Exception in thread "Thread-145" java.net.SocketException: Connection reset Or

Configuration error[Cannot connect to database [default]] (Configuration.scala:559)

When reusing the same FakeApplication: SQLException: Attempting to obtain a connection from a pool that has already been shutdown.

I think this is much more logical than always creating a new application for each block "in" or adding all the tests to one block.

+9
source share

All Articles