How to use guice dependency injection in Play tests (Play 2.6.3) - scala

I have a test specification called MyTestSpec. The aim it is to test a controller that uses dependency injection in its constructor.
class StatusController #Inject()(cc: ControllerComponents, counter: Counter) extends AbstractController(cc) { ...
The Counter class is another controller that provides a status over to the other. When I now try to test this controller, I have the option to either mock the required Counter class, construct the whole chain of controllers / dependencies or inject it. Let's ignore mocking for now, although it probably would be the more correct thing to do.
The issue is that always when I try to inject the Counter controller, I get a NullPointerException.
What I tried so far:
Inject the Counter into the constructor of MyTestSpec, but then MyTestSpec won't even be constructed and tested.
Inject into a local var with the #Inject annotation.
Inject into a val via app.injector.instanceOf[Counter].
Inject via the shortform inject[Counter].
All don't actually give me this other Controller.
Below a rough outline of the test, the new application to get started with Play can be easily adjusted to demonstrate the issue:
class MyTestSpec extends PlaySpec with GuiceOneAppPerTest with Injecting {
"StatusController GET" should {
"render the status page from a new instance of controller" in {
val controller = new StatusController(stubControllerComponents(), counter)
...
}
}
The question: is there a way to simply inject this Counter controller? If there is no simple way, the follow on question would be what components I can then inject anyway if I am already being restrained... ?
Note: this is different to the question asked here, although I tried the solution provided in it.
Note 2: thank you to the Play and ScalaTest developers as well as all these contributors behind the scenes - a wonderful framework.

Related

Using dependency injection in a Game of Life to inject new rules

I have a course project that is a refactor of Game of Life in Scala. It's a
simple pure Scala + SBT project. One of my tasks is to extract the game logic
from GameEngine class and make easier to add new rules, as Conway, Highlife or
anything like that. I turned GameEngine into an abstract class and made all
classes that inherit from it implement methods to decide when cells should die or
reborn. When my game is starting, I have this code:
def addGameMode(gameMode:GameEngine) {
modes += gameMode
}
addGameMode(ConwayEngine)
addGameMode(EasyMode)
addGameMode(HighLife)
addGameMode(Seeds)
And my classes that depends on the GameEngine rule receives it as a
construct parameter. When I need to change the game rule, I use an setter method, like
the code below:
class GameView( var gameEngine: GameEngine, modes: MutableList[GameEngine] ) extends JFXApp {
...
def setGameEngine(g: GameEngine) {
gameEngine = g
}
...
}
I don't know if this approach is correct but, from what I learned, the dependency
injection is correct. But, for my teacher, it isn't. And there my problems began.
According to him, the dependency should be declared in a .xml file and treated by
an external lib. He recommended Spring but I don't know how I should implement
the dependency injection in simple Scala + SBT project using a web framework.
Hopefully, I can ignore this recommendation to use Spring and use another lib.
I found MacWire but I don't know how to use it
to solve this problem. Can someone help me?

How to use different object injections in Xtext tests than in productive environment?

I try to start unit testing a mid size Xtext project.
The generator currently relies on some external resources that I would like to mock inside my test. Thus, I inject the needed object via #Inject into the Generator class.
e.g in pseudocode:
class MyGenerator implements IGenerator{
#Inject
ExternalResourceInterface resourceInterface;
...
}
I create the actual binding inside the languages RuntimeModule:
class MyRuntimeModule{
...
#Override
public void configure(Binder binder) {
super.configure(binder);
binder.bind(ExternalResourceInterface .class).to(ExternalResourceProductionAcess.class);
}
...
}
This works fine for the production environment.
However, in the generator test case, I would like to replace the binding with my mocked version, so that the following call to the CompilationTestHelper uses the mock:
compiler.assertCompilesTo(dsl, expectedJava);
Question:
Where do I tell guice/Xtext to bind the injection to the mock?
If you annotate your test case with RunWith and InjectWith, your test class will be injected via a specific IInjectorProvider implementation.
If that injector provider uses a custom module (like you have shown), the test case gets injected using that configuration. However, you have to make sure you use this injector throughout the test code (e.g. you do not rely on a registered injector, etc.).
Look for the following code as an example (have not compiled it, but this is the base structure you have to follow):
#RunWith(typeof(XtextRunner))
#InjectWith(typeof(LanguageInjectorProvider))
public class TestClass {
#Inject
CompilationTestHelper compiler
...
}

Use WSClient in scala app (play framework)

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.

How to get application.conf variable in an object using Scala and Play 2.5.x?

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.

Injecting with roboguice on non-activity class

Is there any way to inject custom bindings in a class that's not an activity (a class that doesn't extends RoboActivitiy? Because everytime I try to inject it, I get a NullPointerException when accessing it.
I've solved it getting the injector and doing it by myself... but that's something I don't feel comfortable with.
Thanks!
If the class isn't itself created through injection, then obtaining the injector is the right (and only) way to do it. That's how RoboActivity (see onCreate()) does it in the first place. Objects created through injection get their members Injected by the injector.