Reputation: 1994
My Application depends on a custom class that inherits from trait SystemComponent.
package com.example
trait SystemWrapper { ... }
trait MySystemWrapper extends SystemWrapper { ... }
class RealSystemWrapper extends MySystemWrapper { dao: RealDAOFactory =>
val blah = new MySystem("Production")
}
in my Application.scala injecting RealSystemWrapper works and compiles just fine but doesn't help me with testing:
class Application @Inject() (syswrap: RealSystemWrapper) extends Controller
{
...// use syswrap here
}
I would like to use a MockedSystemWrapper extends SystemWrapper
with a mocked DAO factory, etc etc. Therefore I would like to inject the trait SystemWrapper like so
class Application @Inject() (syswrap: SystemWrapper) extends Controller
{
but I get ProvisionException: No implementation was bound
1) No implementation for com.example.SystemWrapper was bound.
while locating com.example.SystemComponent
for parameter 0 at com.example.controllers.Application.<init>(Application.scala:25)
while locating com.example.controllers.Application
for parameter 1 at router.Routes.<init>(Routes.scala:27)
while locating router.Routes
while locating play.api.inject.RoutesProvider
while locating play.api.routing.Router
for parameter 0 at play.api.http.JavaCompatibleHttpRequestHandler.<init>(HttpRequestHandler.scala:200)
while locating play.api.http.JavaCompatibleHttpRequestHandler
while locating play.api.http.HttpRequestHandler
for parameter 4 at play.api.DefaultApplication.<init>(Application.scala:221)
at play.api.DefaultApplication.class(Application.scala:221)
while locating play.api.DefaultApplication
while locating play.api.Application
Play docs suggest I use @ImplementedBy[classOf[RealSystemWrapper]]
decorator but that leaves me with the testing question: how do I change that at testing to classOf[MockedSystemWrapper]
?
Upvotes: 0
Views: 385
Reputation: 8403
As Application
depends on a trait, you need to define the "binding" (ie. which concrete class to use). One approach is, as you described, the @ImplementedBy
annotation. Another approach would be to define the binding in a module as described here: https://www.playframework.com/documentation/2.5.x/ScalaDependencyInjection#Programmatic-bindings
Now if you want to use a different instance in your test, that depends on your test setup. In the simplest case, you're instantiating Application
directly in your test and therefore you can pass in the mock by hand. If you're running the entire application you class, then you can override the bindings (as described here: https://www.playframework.com/documentation/2.5.x/ScalaTestingWithGuice#Override-bindings) or pass the overridden modules to the WithApplication
helper (as shown here: https://www.playframework.com/documentation/2.5.x/ScalaFunctionalTestingWithSpecs2)
Upvotes: 2