Overriding Guice bindings in Play
I'm writing some unit tests for a Play application in which I'd like to override some bindings established in the application's Guice module. It seems to me there are some unstated assumptions in the Play documentation about overrides and I'd like to know what they are.
At https://www.playframework.com/documentation/2.6.x/ScalaTestingWithGuice it says
Bindings can be overridden using Play bindings, or modules that provide bindings. For example: val application = new GuiceApplicationBuilder() .overrides(bind[Component].to[MockComponent]) .build()
Here's the start of a test I'm writing; you might recognize pieces of the Silhouette authorization library:
class FakeOatApplicationsSpec extends OatSpec with GuiceOneAppPerSuite {
private val user = UserFakes.advisor
override def fakeApplication(): Application = new GuiceApplicationBuilder()
.overrides(
bind[AuthenticatorService[CookieAuthenticator]].to[FakeCookieAuthenticatorService],
bind[UserService].to[FakeUserServiceImpl],
bind[UserIdentity].toInstance(user)
).build()
Tests which check the injected classes directly pass. This one ensured the injector is returning an object of the expected type and that the object has the expected behaviour.
"should inject the overridden CookieAuthenticator" in {
val injectAuth = app.injector.instanceOf[AuthenticatorService[CookieAuthenticator]]
assertResult("oat.server.test.FakeCookieAuthenticatorService") {injectAuth.getClass.getName}
val cookieAuth = await {injectAuth.retrieve(FakeRequest())}
assertResult(user.userid.toString) {cookieAuth.get.loginInfo.providerKey}
}
However, if I get an injected controller and look for the expected behaviour there, the tests fail. In particular, the behaviour I'm expecting is that the controller's Request
object has the injected user embedded into it. The user I actually see is the one that comes from the supposedly overridden CookieAuthenticator in the application's Module bindings. So in some cases, the override is ignored.
In the application's module the AuthenticatorService[CookieAuthenticator]
is provided by an @Provides
function. I don't know if that makes a difference or not.
Furthermore, I note that the injector will provide objects of some types but not others. For example, app.injector.instanceOf[FakeController]
provides the expected object. It uses an @Inject()
annotation. app.injector.instanceOf[UserDAO]
succeeds. It's bound in the application's module. But app.injector.instanceOf[Silhouette[OatEnv]]
fails with a "No implementation for com.mohiva.play.silhouette.api.Silhouette was bound." error. But Guice must know about it because it's injected into the FakeController
it happily returned. This binding is the first one in the application's module:
class ServerModule(environment: play.api.Environment,
configuration: Configuration
) extends AbstractModule with ScalaModule with Logger {
def configure() {
bind[Silhouette[OatEnv]].to[SilhouetteProvider[OatEnv]] // injector fails
bind[UserDAO].to[UserDAOAnormImpl] // injector works
...
A similar (unanswered) question is asked at Play Framework 2.4.x - Override Guice Binding. In a 2011 post on the Guice google group (https://groups.google.com/forum/#!topic/google-guice/naqT-fOrOTw) there is reference to overrides in a "child injector" and that Guice, by design, does not allow it. Is that my situation? I don't see any reference to "child injectors" in either the current Play documentation or the current Guice documentation.
So, in summary, what kinds of overrides are permitted and which are not? Why can I get some objects from the injector but not others?
链接地址: http://www.djcxy.com/p/94656.html上一篇: 序列作为列的默认值
下一篇: 在Play中重写Guice绑定