Skip to content

Instantly share code, notes, and snippets.

@leogrim
Created July 23, 2013 04:51
Show Gist options
  • Save leogrim/7e18514d2976b9d20fa3 to your computer and use it in GitHub Desktop.
Save leogrim/7e18514d2976b9d20fa3 to your computer and use it in GitHub Desktop.
Dependency Injection and Testing at FortyTwo Inc.More in our blog post: "Lightweight Testing with Custom Guice Injectors" http://eng.kifi.com/lightweight-testing-with-custom-guice-injectors/
package com.yourApplication.inject
import com.google.inject._
import net.codingwell.scalaguice.InjectorExtensions.ScalaInjector
import net.codingwell.scalaguice.ScalaModule
import com.google.inject.util.Modules
import play.api.Mode._
import play.api.Mode
import java.util.concurrent.atomic.AtomicBoolean
import com.yourApplication.YourApplicationGlobal
sealed trait InjectorProvider {
def mode: Mode
def module: Module
def injector: Injector
implicit def richInjector(injector: Injector): ScalaInjector = new ScalaInjector(injector)
protected def createInjector(modules: Module*) = {
val modeModule = new ScalaModule {
def configure(): Unit = bind[Mode].toInstance(mode)
}
val modulesWithMode = modules :+ modeModule
val stage = mode match {
case Mode.Dev => Stage.DEVELOPMENT
case Mode.Prod => Stage.PRODUCTION
case Mode.Test => Stage.DEVELOPMENT
case m => throw new IllegalStateException(s"Unknown mode $m")
}
Guice.createInjector(stage, modulesWithMode: _*)
}
def withInjector[T](overridingModules: Module*)(f: Injector => T) = {
val customModules = Modules.`override`(module).`with`(overridingModules:_*)
val injector = createInjector(customModules)
f(injector)
}
def inject[A](implicit m: Manifest[A], injector: Injector): A = injector.instance[A]
def provide[T](func: => T): Provider[T] = new Provider[T] { def get = func }
}
trait EmptyInjector extends InjectorProvider {
private val creatingInjector = new AtomicBoolean(false)
private val _initialized = new AtomicBoolean(false)
def initialized = _initialized.get
lazy val injector: Injector = {
if (creatingInjector.getAndSet(true)) throw new Exception("Injector is being created!")
val injector = createInjector(module)
_initialized.set(true)
injector
}
}
trait ApplicationInjector extends InjectorProvider {
import play.api.Play.current
private def yourApplicationGlobal = current.global.asInstanceOf[YourApplicationGlobal]
def module = yourApplicationGlobal.module
def mode = yourApplicationGlobal.mode
implicit def injector = yourApplicationGlobal.injector
}
package com.yourApplication.test
import com.google.inject.Module
import com.google.inject.util.Modules
import play.api.Mode._
import play.api.Mode
import com.yourApplication.YourApplicationGlobal
import com.yourApplication.inject.EmptyInjector
import java.io.File
class TestApplicationFromGlobal(override val path: File, _global: YourApplicationGlobal)
extends play.api.test.FakeApplication(path = path) {
override lazy val global = _global
}
class TestGlobal(defaultModules: Seq[Module], overridingModules: Seq[Module]) extends YourApplicationGlobal(Test) {
val module = Modules.`override`(defaultModules:_*).`with`(overridingModules: _*)
override val initialized = true
}
class TestApplication(overridingModules: Module*)(implicit path: File = new File("./yourApplication/"))
extends TestApplicationFromGlobal(path, new TestGlobal(Seq(SomeDefaultModule(), AnotherDefaultModule()), overridingModules))
trait TestInjector extends EmptyInjector {
val mode = Mode.Test
lazy val module = Modules.combine(SomeDefaultModule(), AnotherDefaultModule())
}
import play.api._
abstract class YourApplicationGlobal(val mode: Mode.Mode) extends GlobalSettings with EmptyInjector {
val module: ScalaModule
// Your Application Global settings
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment