Disable singleton when testing with ScalaTest in Play for Scala - scala

I have the following #Singleton in my Play for Scala application that loads on startup:
#Singleton
class Scheduler #Inject()(#Named("mainEtl") mainEtl: ActorRef, system: ActorSystem) {
// some code
}
This is the module where Scheduler is declared. The module is enabled in application.conf:
class Module extends AbstractModule {
def configure() = {
bind(classOf[Scheduler]).asEagerSingleton
}
}
And the related module definition to configure the #Named injected object, also declared in application.conf:
class AkkaBindings extends AbstractModule with AkkaGuiceSupport {
def configure = {
bindActor[MainEtl]("mainEtl")
}
}
When I run any ScalaTest test, apparently the singleton starts running because I get an error saying that it doesn't find MainEtl (the object injected in the Scheduler class). The point is that I don't need to run the singleton for my tests, so I need to disable it.
This is how I invoke the Play application in my tests:
class ManageBanksTest extends PlaySpec with OneAppPerSuite with MockitoSugar {
implicit override lazy val app = new GuiceApplicationBuilder().build
// more test code
}
This is how I tried to disable it, but it doesn't work as I get the same error:
implicit override lazy val app = new GuiceApplicationBuilder()
.disable[Scheduler]
.build
Alternatively, I could mock Scheduler, but I would have to mock also the #Named injected object and I couldn't find information on how to achieve that.
Any ideas?

This is the solution: to disable the Module class not to declare Scheduler as singleton:
implicit override lazy val app = new GuiceApplicationBuilder()
.disable[Module]
.build

import com.google.inject.AbstractModule
import com.google.inject.name.Names
import org.specs2.mock.Mockito
import play.api.inject.guice.{GuiceApplicationBuilder, GuiceableModule}
val modules = Option(new AbstractModule {
override def configure() = {
val mockMainETL = mock[MainEtl]
bind(classOf[ActorRef])
.annotatedWith(Names.named("mainEtl"))
.toInstance(mockMainETL)
val mock1 = mock[ManageBanksDAO]
mock1.readMany answers { _ => Future{seqMany}}
val mockManageBanks = mock[ManageBanks]
bind(classOf[ManageBanks]).toInstance(new ManageBanks(mock1))
}
})
lazy val app = new GuiceApplicationBuilder()
.overrides(modules.map(GuiceableModule.guiceable).toSeq: _*)
.build
Try configuring your mock inside modules and add those modules while initializing your application. This will inject custom mocks.
Also instead of this :
val controller = new ManageBanks(mock1)
Try this:
val controller = app.injector.instanceOf(classOf[ManageBanks])

Related

How to execute action on Play framework startup?

I have this application using Play framework with Scala and I want to have a service that executes a method on startup of my application. I am doing everything that is said at How do I perform an action on server startup in the Scala Play Framework?. My version of Play is 2.6 and I am not using GlobalSettings for this.
package bootstrap
import com.google.inject.AbstractModule
class EagerLoaderModule extends AbstractModule {
override def configure() = {
println("EagerLoaderModule.configure")
bind(classOf[InitSparkContext]).to(classOf[InitSparkContextImpl]).asEagerSingleton()
}
}
On the application.conf I included the line play.modules.enabled += "bootstrap.EagerLoaderModule". Below is my Service that I want to start Spark context.
package bootstrap
import javax.inject.{Inject, Singleton}
import play.api.inject.ApplicationLifecycle
import scala.concurrent.Future
trait InitSparkContext {
def init(): Unit
def stop(): Unit
}
#Singleton
class InitSparkContextImpl #Inject()(appLifecycle: ApplicationLifecycle) extends InitSparkContext {
override def init(): Unit = println("InitSparkContext.start")
override def stop(): Unit = println("InitSparkContext.stop")
appLifecycle.addStopHook { () =>
stop()
Future.successful(())
}
init()
}
Nothing is printed on the console, even println("EagerLoaderModule.configure") is not printed....
You can't use println on play application, you'll need to set up a Logger. So:
val log = play.api.Logger(getClass)
log.info("This happened")
Then you can use the logback file to configure your log files:
Here are some details on how to configure it:
https://www.playframework.com/documentation/2.6.x/SettingsLogger

Play Slick: How to write in memory unit test cases using Play and Slick

I am using Play 2.6 and Slick 3.2 with MySql database. But the problem is that I am not able to write test cases using h2 database. The problem is that, by using guice, I am not able to inject DatabaseConfigProvider in my repo. Following is my repo class implementation:
class CompanyRepoImpl #Inject() (dbConfigProvider: DatabaseConfigProvider)
(implicit ec: ExecutionContext) extends CompanyRepo {
val logger: Logger = LoggerFactory.getLogger(this.getClass())
private val dbConfig = dbConfigProvider.get[JdbcProfile]
import dbConfig._
import profile.api._
private val company = TableQuery[Companies]
------
}
My test case class:
class CompanyRepoSpec extends AsyncWordSpec with Matchers with BeforeAndAfterAll {
private lazy val injector: Injector = new GuiceApplicationBuilder()
.overrides(bind(classOf[CompanyRepo]).to(classOf[CompanyRepoImpl]))
.in(Mode.Test)
.injector()
private lazy val repo: CompanyRepo = injector.instanceOf[CompanyRepo]
private lazy val dbApi = injector.instanceOf[DBApi]
override protected def beforeAll(): Unit = {
Evolutions.applyEvolutions(database = dbApi.database("test"))
}
override protected def afterAll(): Unit = {
Evolutions.cleanupEvolutions(database = dbApi.database("test"))
}
-----------------------
}
Testing application.test.conf
play.evolutions.db.test.enabled=true
play.evolutions.autoApply=true
slick.dbs.test.profile="slick.jdbc.H2Profile$"
slick.dbs.test.db.driver="org.h2.Driver"
slick.dbs.test.db.url="jdbc:h2:mem:test;MODE=MySQL"
May be, my configuration are not valid for testing, so, how can we write test cases using scala, slick and play.

How can a custom ApplicationLoader start Dependency Injecting Actors and get tested?

In "Dependency Injecting Actors" it's shown how to inject a parameter into the constructor of a child actor. The parent actor uses injectedChild to be allowed to pass to the child (at child creation time) only the non-injected parameter and then let Guice inject the rest. To do this, it extends InjectedActorSupport and gets the child's factory injected in the constructor:
class MyParent #Inject() (childFactory: MyChild.Factory,
#Assisted something: Something,
#Assisted somethingElse: SomethingElse) extends Actor with InjectedActorSupport
[..]
val child: ActorRef = injectedChild(childFactory(something, somethingElse), childName)
But what about the class that starts the parent and is not an actor but a custom ApplicationLoader?
How can I start the parent actor from there? No mention of this is in the documentation.
I tried doing the same for the loader as I did for parent:
class MyLoader #Inject() (parentFactory: MyParent.Factory) extends ApplicationLoader with Actor with InjectedActorSupport {
[..]
val parent = injectedChild(parentFactory(something, somethingElse), parentName)
would this be correct? How can I test it?
class MyModule extends AbstractModule with AkkaGuiceSupport {
def configure = {
bindActor[MyParent](parentName)
bindActor[MyLoader](loaderName)
bindActorFactory[MyChild, MyChild.Factory]
bindActorFactory[MyParent, MyParent.Factory]
}
}
So:
How do I start the parent from MyLoader while letting Guice dependency-inject what's required?
How can I test MyLoader?
This has been my test so far but now I need to pass the injected thingy to MyLoader and I don't know how (note the ***???**** in place of the argument which I do not know where to find):
class MyLoaderSpec(_system: ActorSystem, implicit val ec: ExecutionContext) extends TestKit(_system) with WordSpecLike with BeforeAndAfterAll with Matchers {
val loader = new SimstimLoader(???)
override def beforeAll(): Unit = {
loader.load(ApplicationLoader.createContext(new Environment(new File("."), ApplicationLoader.getClass.getClassLoader, Mode.Test)))
}
Thanks a million in advance!
Here is how I solved this issue.
--> How to start a parent actor who needs dependency-injection.
First of all, manually starting such an actor is impossible if you, like me, need to dependency-inject an instance which you do not know how to pass and where from. The solution is to let Guice start the actor automagically. Here is how.
First, create your binder module for Guice:
class MyModule extends AbstractModule with AkkaGuiceSupport{
override def configure(): Unit = {
bindActor[Root](Root.NAME)
bind(classOf[StartupActors]).asEagerSingleton()
}
}
Then, tell Play where your binder module is located by adding the following in your conf/application.conf:
play.modules={
enabled += "my.path.to.MyModule"
}
The StartupActors is simply a class I use to log whenever the automagic start of dependency-injected actors actually takes place. I log the event so that I can be sure of when and whether it occurs:
class StartupActors #Inject() (#Named(Root.NAME) root: ActorRef) {
play.api.Logger.info(s"Initialised $root")
}
The Root actor in my case takes care of parsing a custom configuration. Since the resulting vars from the parsing is required by my parent actor and during the tests I need to mock such resulting vars, I delegate the parsing to an actor other than the parent actor, i.e., the Root actor:
object Root {
final val NAME = "THERoot"
case class ParseConfiguration()
}
class Root #Inject()(configuration: Configuration, projectDAO: ProjectDAO) extends Actor {
val resultingVar: Something = myConfigParsing()
override def preStart(): Unit = {
context.actorOf(Props(new MyParent(resultingVar: Something, somethingElse: SomethingElse, projectDAO: ProjectDAO)))
}
override def receive: Receive = {
case ParseConfiguration => sender ! myConfigParsing()
case _ => logger.error("Root actor received an unsupported message")
}
}
The ParseConfiguration message is used uniquely for testing purposes. Normally the configuration parsing occurs instead because of the initialisation of the resultingVar attribute.
This way, MyParent wont need to get anything injected. Only StartupActors and Root will get injected. MyParent will simply get projectDAO from Root and pass it on to all its children.
class MyParent(something: Something, somethingElse: SomethingElse, projectDAO: ProjectDAO) extends Actor { ... }
Finally, for completion, I'm reporting here how I wrote the tests since I had troubles finding enough information online around this as well.
import akka.actor.{ActorRef, ActorSystem, Props}
import akka.testkit.{TestKit, TestProbe}
import com.typesafe.config.ConfigFactory
import org.mockito.Mockito.mock
import org.scalatest.{BeforeAndAfterAll, WordSpecLike}
import org.specs2.matcher.MustMatchers
import play.api.Configuration
import scala.concurrent.ExecutionContext
class RootSpec(_system: ActorSystem) extends TestKit(_system)
with WordSpecLike with BeforeAndAfterAll with MustMatchers {
implicit val ec: ExecutionContext = scala.concurrent.ExecutionContext.global
val conf: com.typesafe.config.Config = ConfigFactory.load()
val configuration: Configuration = Configuration(conf)
val projectDAOMock: ProjectDAO = mock(classOf[ProjectDAO])
private var mainActor: ActorRef = _
private var something: Something = Something.empty
def this() = this(ActorSystem("MySpec"))
override def afterAll: Unit = {
system.shutdown()
}
override def beforeAll(): Unit = {
mainActor = system.actorOf(Props(new Root(configuration, projectDAOMock)), Root.NAME)
}
"RootSpec: Root Actor" should {
val probe = TestProbe()
"successfully parse the configuration file" in {
probe.send(mainActor, ParseConfiguration)
something = probe.expectMsgPF() {
case msg => msg.asInstanceOf[Something]
}
}
}
}
and then I test MyParent by conveniently providing mock objects in place of vars resulting from the configuration parsing:
import akka.actor.{ActorRef, ActorSystem, Props}
import akka.testkit.{TestKit, TestProbe}
import org.mockito.Mockito
import org.mockito.Mockito._
import org.scalatest.{BeforeAndAfterAll, WordSpecLike}
import org.specs2.matcher.MustMatchers
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.{ExecutionContext, Future}
case class AnyProjectAPI(val projectAPI: ProjectAPI) extends AnyVal
class MyParentSpec(_system: ActorSystem, implicit val ec: ExecutionContext) extends TestKit(_system)
with WordSpecLike with BeforeAndAfterAll with MustMatchers {
val something = mock(classOf[Something])
val somethingElse = mock(classOf[somethingElse])
val projectDAOMock: ProjectDAO = mock(classOf[ProjectDAO])
val projectTest: ProjectAPI = new ProjectAPI(allMyRandomConstructorArguments),
val projectsList: List[ProjectAPI] = List(projectTest)
val expectedCreationId = 1
private var parent: ActorRef = _
def this() = this(ActorSystem("MySpec"), scala.concurrent.ExecutionContext.global)
override def afterAll: Unit = {
system.shutdown()
}
override def beforeAll(): Unit = {
parent = system.actorOf(Props(new MyParent(something, somethingElse, projectDAOMock)), MyParent.NAME)
}
"MyParentTesting: parent's pull request" should {
when(myProjApi.getAllProjects).thenReturn(Future {projectsList})
val anyProject: AnyProjectAPI = AnyProjectAPI(org.mockito.Matchers.any[ProjectAPI])
Mockito.when(projectDAOMock.create(org.mockito.Matchers.any[ProjectAPI]))
.thenReturn(Future {expectedCreationId}: Future[Int])
val probe = TestProbe()
val probe1 = TestProbe()
"be successfully satisfied by all children when multiple senders are waiting for an answer" in {
probe.send(parent, UpdateProjects)
probe1.send(parent, UpdateProjects)
allChildren.foreach(child =>
probe.expectMsg(expectedCreationId))
allChildren.foreach(child =>
probe1.expectMsg(expectedCreationId))
}
}
}

Play! Scala: How to disable actor modules loaded at the start of the application when testing?

I load some actors at the beginning of my Play! 2.5 application like this:
class Module extends AbstractModule with AkkaGuiceSupport with ScalaModule {
override def configure() = {
bindActor[MainSupervisor]("main-supervisor")
}
}
The problem is that when I run my tests I got a lot a logs (and unnecessary calls) from the loaded actor (and the entire cluster and remote system) like
[INFO ] a.r.Remoting: Starting remoting
[INFO ] a.r.Remoting: Remoting started; listening on addresses :[akka.tcp://application#127.0.0.1:41496]
[INFO ] a.r.Remoting: Remoting now listens on addresses: [akka.tcp://application#127.0.0.1:41496]
I have, for instance, a class that I test where I don't need any actor, but I don't find any way to disable them (or even better the entire actor system).
What I have tried is:
lazy val appWithoutActorsBuilder = new GuiceApplicationBuilder()
.disable[ActorSystem]
.disable[MainSupervisor]
.build()
lazy val injectorWithoutActors = appWithoutActorsBuilder.injector
lazy val wSClientWithoutActors = injectorWithoutActors.instanceOf[WSClient]
lazy val ec = scala.concurrent.ExecutionContext.Implicits.global
lazy val facebookAPI = new FacebookAPI(wSClientWithoutActors, ec)
But when I test the FacebookAPI methods (e.g. facebookAPI.method(...) mustBe ...) I still see the logs from Akka. What can I do in order to avoid it?
You have to disable your module instead of your actor. So, considering that you have this class:
package com.acme.modules
class Module extends AbstractModule with AkkaGuiceSupport with ScalaModule {
override def configure() = {
bindActor[MainSupervisor]("main-supervisor")
}
}
And that you are registering it at your conf/application.conf like this:
play.modules.enabled += "com.acme.modules.Module"
Then, at your tests, your have to do the following:
lazy val appWithoutActorsBuilder = new GuiceApplicationBuilder()
.disable[com.acme.modules.Module]
.build()

How to define onStart method in scala play framework 2.4

how can i define startup job in play framework 2.4 with scala?
play framework GlobalSetting
I have already:
class StartupConfigurationModule extends AbstractModule{
override def configure(): Unit = {
Akka.system.scheduler.schedule(Duration(0,duration.HOURS),Duration(24,duration.HOURS))(Id3Service.start())
Akka.system.dispatcher
}
}
You need to register this in the modules.enabled of your application (in application.conf).
It should schedule a call to start on the Id3Service after 0 hours and then every 24 hours.
The issue is that the module doesn't declare a dependency on a running application, or more interestingly on a started actorSystem. Guice can decide to start it before the app is initialized.
The follwing is one way to force the dependency on the initialized actorSystem (and reduce the footprint of your dependency)
import javax.inject.{ Singleton, Inject }
import akka.actor.ActorSystem
import com.google.inject.AbstractModule
import scala.concurrent.duration._
class StartupConfigurationModule extends AbstractModule {
override def configure(): Unit = {
bind(classOf[Schedule]).asEagerSingleton()
}
}
#Singleton
class Schedule #Inject() (actorSystem: ActorSystem) {
implicit val ec = actorSystem.dispatcher
actorSystem.scheduler.schedule(Duration(0, HOURS), Duration(24, HOURS))(Id3Service.start())
}
object Id3Service {
def start(): Unit = println("started")
}