Question

I've been following the Scala testing examples using Specs2 from the official Play documentation. I notice that they use WithApplication to start up a fake application to test against, with clode like the following:

"something" should {
    "do X" in new WithApplication { /* ... */ }
    "do Y" in new WithApplication { /* ... */ }
    "do Z" in new WithApplication { /* ... */ }
}

This is fine and all, but the problem that I'm having is that I incur the cost of my application starting up each time this happens. This isn't necessarily "fast" or at least not fast enough once your test-suite grows to a reasonable size. I've tried doing things like:

val app = FakeApplication()
"something" should {
    "do X" in new WithApplication(app) { /* ... */ }
    "do Y" in new WithApplication(app) { /* ... */ }
    "do Z" in new WithApplication(app) { /* ... */ }
}

and

"something" should {
    val app = FakeApplication()
    Helpers.running(app) {
        "do X" in { /* ... */ }
        "do Y" in { /* ... */ }
        "do Z" in { /* ... */ }
    }
}

The first seems to work for the first test and then complains about db connection issues on the later tests. I'm guessing something is getting shutdown here or something (not sure what).

The second doesn't work at all because it complains about there being no running application, which I'm not sure about either.

Any help is greatly appreciated. Thanks!

Was it helpful?

Solution

Well, it depends on what you want to test. If you're just unit testing code that has no external dependencies or dependencies that you can mock or stub out (and it would be a good idea to structure your code in such a way that allows this), then you don't need to use WithApplication. This is probably the best approach.

The first solution you provided doesn't work because applications can only be used once. It's WithApplication that starts and stops your application, so even if that did work, you wouldn't get any performance benefit.

The second solution you provided doesn't work because when the Helpers.running(app) { } code block runs, this is only declaring the specs. Specs puts all these in a list, and then you exit the running block and it shuts down the app. Then at some point later, specs runs the tests, and there's no application of course then.

So, if you can't test your code in isolation of the rest of your app, then you need to have a running app, there's nothing you can do about that, it's the reality of integration testing. And you probably want it started and shutdown between each test, otherwise your tests aren't running in isolation of each other.

OTHER TIPS

It's outdated, but I'll give my answer. Since I faced same problem, and had similar idea. There is AfterAll & BeforeAll traits in spec2, maybe it was not there at the time of post, so my solution is basically:

package com.equipx.spec.util

import org.specs2.specification.{AfterAll, BeforeAll}
import play.Application
import play.api.Play
import play.test.{Helpers, FakeApplication}

/**
 * @author Anton Oparin (antono@clemble.com)
 */
trait WithGlobalApplication extends BeforeAll with AfterAll {

  protected var app: Application = null

  /**
   * Override this method to setup the application to use.
   *
   * By default this will call the old {@link #provideFakeApplication() provideFakeApplication} method.
   *
   * @return The application to use
   */
  protected def provideApplication: Application = {
    return provideFakeApplication
  }

  /**
   * Old method - use the new {@link #provideApplication() provideApplication} method instead.
   *
   * Override this method to setup the fake application to use.
   *
   * @return The fake application to use
   */
  protected def provideFakeApplication: FakeApplication = {
    return Helpers.fakeApplication
  }

  override def beforeAll {
    app = provideApplication
    Helpers.start(app)
    Play.current
  }

  override def afterAll {
    if (app != null) {
      Helpers.stop(app)
      app = null
    }
  }

}

Basically I took WithApplication implementation, and made it global.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top