Created
July 23, 2013 04:51
-
-
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/
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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()) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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