Running tests as described here
"Spec" should {
"example" in new WithApplication {
...
}
}
is unacceptably slow for me. This is because new WithApplication is starting and stoping framework at every example. Don't get me wrong, a framework itself loads very fast, but if database is configured (surprise!), situation becomes terrible.
Here are some measurments:
"The database layer" should {
"test1" in {
1 must be equalTo(1)
}
...
"test20" in {
1 must be equalTo(1)
}
}
Execution time: 2 seconds. Same test with WithApplication at every example consumes 9 seconds
I was able to achive 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: performance boost
Cons:
need to copy-paste setup and tear-down code because don't know how to reuse it (by 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()
}
}
so I can't completely emulate Helpers.running behaviour (resetClient is not visible for my code) without reflection.
Please suggest how to break cons or different approach how accomplish my issue.
I don't know if it is the best possible solution but in this thread: Execute code before and after specification
You can read a solution for reusable code. I implemented it with little modifications. For me the beforeAll step did not run 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 the map
would be better with Step(...) ^ fragments ^ Step(...)
but it did not run the beforeAll for me. The user guide (http://bit.ly/11I9kFM) at "Global setup/teardown" says to use a lazy val.
Overall it was a pain to set up this. 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 it is much more logical this way than always creating a new application for every "in" block or adding all tests into one block.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With