Playframework recently made guice its’ default dependency injection (DI) framework. So I was looking for a simple example where a controller defines a dependency which then get’s overridden for a FakeApplication in a test. I expected a simple gist in the docs for this very common (I thought) use case, but didn’t find one. Here is what I ended up with, which is based on ScalaTest + Play.

The nice thing about this setup is that it always tests the whole app, incl. the routing. Often developers only test a specific controller method, which leaves some space for bugs.

app/controller/PersonController.scala:

class Hello {
  def sayHello(name: String) = "Hello " + name
}

class PersonController @Inject() (hello: Hello) extends Controller {
  def index = Action {
    Ok(hello.sayHello("michael"))
  }
}

test/ApplicationTest.scala:

import controllers._
import org.scalatest._
import org.scalatestplus.play._
import play.api.inject.bind
import play.api.inject.guice.GuiceInjector
import play.api.inject.guice.GuiceableModule
import play.api.test._
import play.api.test.Helpers._

abstract class MyPlaySpec extends WordSpec with Matchers with OptionValues with WsScalaTestClient

class GermanHello extends Hello {
  override def sayHello(name: String) = "Hallo " + name
}

class ApplicationTest extends MyPlaySpec with OneAppPerTestWithOverrides {
  override def overrideModules = Seq(
    bind[Hello].to[GermanHello]
  )

  "render the index page" in {
    val home = route(FakeRequest(GET, "/")).get
    status(home) shouldBe OK
    contentAsString(home) shouldBe "Hallo michael"
  }

}

test/OneAppPerTestWithOverrides.scala:

package org.scalatestplus.play

import play.api.Application
import play.api.inject.guice.GuiceApplicationBuilder
import play.api.inject.bind
import play.api.inject.guice.GuiceableModule
import play.api.test._
import org.scalatest._

trait OneAppPerTestWithOverrides extends SuiteMixin { this: Suite 
  def overrideModules: Seq[GuiceableModule] = Nil

  def newAppForTest(testData: TestData): Application =
    new GuiceApplicationBuilder()
      .overrides(overrideModules: _*)
      .build

  private var appPerTest: Application = _
  implicit final def app: Application = synchronized { appPerTest }

  abstract override def withFixture(test: NoArgTest) = {
    synchronized { appPerTest = newAppForTest(test) }
    Helpers.running(app) {
      super.withFixture(test)
    }
  }
}

A full application (and test) is here, and the discussion on the mailinglist here. More details on guice DI in playframework are in the documentation

PS: another handy tipp: if you want to get the used binding for a given class, you can just ask the guice injector inside a test:

val hello = app.injector.instanceOf(classOf[Hello])