I have DAO defined as follows:
#Singleton
class MyDAO #Inject()(protected val dbConfigProvider: DatabaseConfigProvider) extends HasDatabaseConfigProvider[JdbcProfile] {
I have an integration test which references this DAO:
class SomeIntegrationTest {
lazy val someVal = new MyDAO
}
How can I inject the DatabaseConfigProvider into the MyDAO in the SomeIntegrationTest? I cannot inject one in the constructor of the test because test classes do not take constructor parameters.
You can get your dependency injected by doing
val dbConfigProvider = app.injector.instanceOf[DatabaseConfigProvider]
where app is an instance of your FakeApplication. Without it, there is no way Play can inject your dependency for you. You can get an instance of FakeApplication by extending OneAppPerSuite, see the provided link for more details.
In general, there are three main ways you can gain access to some object(s) in your test:
manual creation of objects using the new keyword (not considered best practice)
injection via injector as shown here (either injecting objects directly or injecting a provider/factory which can get them for you)
in case of unit testing a class with some dependencies, having those dependencies mocked
Related
I'm not sure if there's something really basic that I'm missing, but I can't figure out how to use WSClient. I've seen all of the examples saying you need to pass the WSClient to a class as a dependency, which I've done, but when I run the program what do I actually pass to my class?
For example, my class signature is:
class myClassName(ws: WSClient)
But when I instantiate the class what do I actually pass to it? I'm also happy to ignore the Play! framework stuff if that makes it easier and just use SBT to run it (which I'm more familiar with).
It's unclear where you might be using a WSClient, but it is recommended that you let the Play framework 'manage' the instance of the client. When you instantiate your application, it gets injected:
class Application #Inject() (ws: WSClient) extends Controller {
...
}
What that means is that inside the ... you have access to ws as a value. You can instantiate myClassName using it:
class Application #Inject() (ws: WSClient) extends Controller {
val myclass = myClassName(ws) // passes the injected WSClient to myClassName
}
Or you can write a function that returns the WSClient, so some other area of your code can call into your Application object to get a object handler for it.
But the key is that the Application object gets that handle because of injection, which is the #Inject annotation.
If you need to generate a WSClient and manage it manually, there are good instructions here. The recommended implementation is reliant on Play! framework libraries, but doesn't depend on the Application.
I used to get the application.conf variable in Play 2.4.x with Play.current.configuration.getString('NAME_HERE'), and it was working good in class, object and companion object too.
Now, I'm using Play 2.5.4 with Scala in a new project, and I won't use this Play.current, because it's deprecated, but there is an alternative using DI, like this :
class HomeController #Inject() (configuration: play.api.Configuration) extends Controller {
def config = Action {
Ok(configuration.underlying.getString("db.driver"))
}
}
This DI Injection works like a charm in class, but in this project, I need to get the variable db.driver in a object? And as far I know, with an object I can't use DI.
Maybe using Guice would help?
You can use #Singleton annotated class instead of object
trait Foo {}
#Singleton
class FooImpl #Inject()(configuration: play.api.Configuration)) extends Foo {
//do whatever you want
}
#Singleton makes the class singleton.It feels bit awkward because Scala itself natively have syntax object to create a singleton, But this is the easiest and probably best solution to DI into a singleton.
You also may create the singleton eagerly like the code below.
bind(classOf[Foo]).to(classOf[FooImpl])asEagerSingleton()
for more detail Info, You can look up Google Guice Wiki and Playframework site
EDIT
How you call it is exactly the same as how you DI in Playframework2.5.
class BarController #Inject()(foo: Foo) extends Controller {
//Do whatever you want with Foo
}
Guice basically generates new instance every time you DI, Once you put #Singleton, Guice use only one instance instead.
DI is for anti-high coupling.So when you want to use a class you defined from another class,You need to DI otherwise the classes are highly coupled which end up making it harder to code your unit test.
FYI, You can use them outside of Play with this technique.
Create an Instance of class which does DI via Playframework Guice Independently in Scala
Have you tried
import com.typesafe.config.ConfigFactory
val myConfig = ConfigFactory.load().getString("myConfig.key")
Above approach doesn't require you to convert your object to singleton class.
You can do
Play.current.configuration
however that will (probably) no longer be possible with Play 2.6.
Ideally, however, you would pass the configuration in as a parameter to that method of the object or, use a class instead of an object.
What I somtimes do to migrate 'from object to class':
class MyComponent #Inject() (config: Configuration) {
// here goes everything nice
def doStuff = ???
}
object MyComponent {
#deprecated("Inject MyComponent")
def doStuff = {
val instance = Play.current.injector.instanceOf[MyComponent]
instance.doStuff
}
}
This way, you're not breaking existing code while all users of your methods can slowly migrate to using classes.
First of all, thanks for any effort to try and answer the question.
From the current application injector (play.api.Play.current.injector), how do I get a Named instance of a class?
I tried to cast the injector to a ScalaInjector (net.codingwell.scalaguice.InjectorExtensions.ScalaInjector) and to Guice Injector (com.google.inject.Injector), both unsuccessful.
The problem is that there are only 3 methods to instantiate a class, all of them are overloaded instanceOf[T]
For a normal dependency you would do
play.api.Play.current.injector.instanceOf[ProjectRepo]
When you want to retrieve a named dependency you can do
val qualifier = Some(QualifierInstance(Names.named("name")))
val bindingKey = BindingKey[ProjectRepo](Class[ProjectRepo], qualifier)
play.api.Play.current.injector.instanceOf[ProjectRepo](bindingKey)
Anyway you should only use the injector directly in very rare cases, makes sure there is not a simpler way to retrieve your dependencies.
When you need to inject a named dependency (in my case an ActorRef) you can also use a case class to help:
case class NamedActorHelper #Inject() (#Named("some-actor") actor: ActorRef)
class SomeActorSpec with GuiceOneAppPerSuite {
...
val someActor = app.injector.instanceOf[NamedActorHelper].actor
...
}
Replacing app with play.api.Play.current should also work.
I created a small CRUD application to learn more about Scala and Play. Following the CRUD template, I obtained the solution posted here on GitHub.
I have been struggling to develop effective tests for this using Specs2. Now I would like to test the controller. It has this signature:
class PersonController #Inject() (repo: PersonRepository, val messagesApi: MessagesApi)
(implicit ec: ExecutionContext) extends Controller with I18nSupport
To test an action of the controller, I should create a new controller. While I see how I can mock away the repository and the WithApplication trait will provide the ExecutionContext, I don't see how to deal with the MessagesApi.
1) Shall I create an instance of it or retrieve it from somewhere and pass explicitly? how?
2) Shall I mock it too? how?
Thank you for your help.
For unit tests, I would go with a mock. Both specs2 (docs) and ScalaTest (docs) have some level of integration with Mockito.
For functional tests, I would go with using WithApplication scope (in the case of specs2) and using the app injector to create the controller instance:
"should test using an injected controller" in new WithApplication {
val applicationController = app.injector.instanceOf[controllers.Application]
val result: Future[mvc.Result] = applicationController.index()(FakeRequest())
status(result) must equalTo(OK)
}
This way, Play injector will create your controller instance with all the necessary dependencies, including MessageApi.
In the following, I am using the Play2 ReactiveMongo plugin in version 0.11.0.play24 (https://github.com/ReactiveMongo/Play-ReactiveMongo)
for Play 2.4.
As mentioned in the documentation located at http://reactivemongo.org/releases/0.11/documentation/tutorial/play2.html, a Play2 controller with Mongo is instantiated as follows:
class MyController #Inject() (val reactiveMongoApi: ReactiveMongoApi)
extends Controller with MongoController with ReactiveMongoComponents { }
Therefore, since the controller is now a class and not an object, it is not possible to use it as a singleton in the test cases.
However, I do not know how to inject the reactiveMongoApi in order to instantiate a MyController() with the right parameters in a test case (ScalaCheck or other...)
Do you have any idea/example on how to test such a controller with ScalaCheck or Specs2?
Thank you in advance!
You can produce a mock for ReactiveMongoApi (depending which mock framework you use):
val reactiveMongoApi = mock[ReactiveMongoApi]
and then you can do this:
new MyController(reactiveMongoApi)
That's the simplest approach. To use the actual ReactiveMongoApi object:
val app = new GuiceApplicationBuilder()
.in(Mode.Test)
.configure("play.modules.enabled" -> "play.modules.reactivemongo.ReactiveMongoModule")
.build
val reactiveMongoApi = app.injector.instanceOf[ReactiveMongoApi]
If it gets more complicated, for example, partially mocked nested dependency tree (this is more integration testing than unit testing), you may want to partially mock the Guice framework as explained here.
This project use Guice for dependency injection, Spec2 for testing controllers, and Frisby for testing endpoints.
https://github.com/luongbalinh/play-mongo