Unable to resolve mock[....] in playframework 2.6.17 - scala

I want to mock ReactiveMongoAPI and for this i am writing the below code,
package controllers
import org.scalatest.mockito.MockitoSugar
import org.scalatestplus.play._
import org.scalatestplus.play.guice._
import play.api.test.Helpers._
import play.api.test._
import play.modules.reactivemongo.ReactiveMongoApi
/**
* Add your spec here.
* You can mock out a whole application including requests, plugins etc.
*
* For more information, see https://www.playframework.com/documentation/latest/ScalaTestingWithScalaTest
*/
class HomeControllerSpec extends PlaySpec with GuiceOneAppPerTest with Injecting with MockitoSugar {
val reactiveMongoApi: mock[ReactiveMongoApi]
"HomeController GET" should {
"render the index page from a new instance of controller" in {
val controller = new HomeController(stubControllerComponents(), reactiveMongoApi)
val home = controller.index().apply(FakeRequest(GET, "/"))
It gives me the error that it cannot resolve the mock[...].
Is there any way to resolve this ?

I bet you want to do as follows:
val reactiveMongoApi: ReactiveMongoApi = mock[ReactiveMongoApi]

Related

DatabaseExecutionContext is missing from the Play API

I am following the DB presription provided here. However, the class DatabaseExecutionContext is nowhere near to be found in the play API and, hence, I am unable to import it.
What am I missing?
See the example code here: https://github.com/playframework/play-samples/blob/2.8.x/play-scala-anorm-example/app/models/DatabaseExecutionContext.scala
import javax.inject._
import akka.actor.ActorSystem
import play.api.libs.concurrent.CustomExecutionContext
#Singleton
class DatabaseExecutionContext #Inject()(system: ActorSystem) extends CustomExecutionContext(system, "database.dispatcher")
You need to configure this context as shown by the documentation: https://www.playframework.com/documentation/2.8.x/AccessingAnSQLDatabase#Using-a-CustomExecutionContext
While you already got an answer, I suggest to use a base trait instead, like:
import javax.inject.{Inject, Singleton}
import akka.actor.ActorSystem
import play.api.libs.concurrent.CustomExecutionContext
import scala.concurrent.ExecutionContext
trait DatabaseExecutionContext extends ExecutionContext
#Singleton
class DatabaseAkkaExecutionContext #Inject()(system: ActorSystem)
extends CustomExecutionContext(system, "database.dispatcher")
with DatabaseExecutionContext
The reason is that if you don't, you'll need to bring akka while testing operations requiring this execution context, with the trait, you should be able to write a simple executor for your tests, like:
implicit val globalEC: ExecutionContext = scala.concurrent.ExecutionContext.global
implicit val databaseEC: DatabaseExecutionContext = new DatabaseExecutionContext {
override def execute(runnable: Runnable): Unit = globalEC.execute(runnable)
override def reportFailure(cause: Throwable): Unit = globalEC.reportFailure(cause)
}
EDIT: I have created a detailed post explaining this.

Start testcontainers before Playframework starts up

I want to start testcontainers from a docker-compose file (postgres and kafka instance), before the play application (with slick) starts up. I want this, so I can write a end to end test. I can not seem to figure out how this is possible with Play.
import java.io.File
import com.dimafeng.testcontainers.DockerComposeContainer.ComposeFile
import com.dimafeng.testcontainers.{DockerComposeContainer, ForAllTestContainer}
import com.typesafe.config.ConfigFactory
import org.scalatest.{BeforeAndAfterAll, FunSpec}
import org.scalatestplus.play.guice.GuiceFakeApplicationFactory
import play.api.inject.guice.GuiceApplicationBuilder
import play.api.{Application, Configuration, Environment, Mode}
trait TestFunSpec extends FunSpec with BeforeAndAfterAll with GuiceFakeApplicationFactory {
override def fakeApplication(): Application = new GuiceApplicationBuilder()
.in(Environment(new File("."), getClass.getClassLoader, Mode.Test))
.loadConfig(_ => Configuration(ConfigFactory.load("test.conf")))
.build
}
class TestIntegrationSpec extends TestFunSpec with ForAllTestContainer {
override val container = DockerComposeContainer(ComposeFile(Left(new File("docker-compose.yml"))))
it("should test something") {
assert(true)
}
}
Scala version 2.12.10
Testcontainer version 0.35.0
Play slick version 5.0.0
When I execute the test without "TestFunSpec", the docker-compose spins up my services correctly. When I add the play application "TestFunSpec" in scope, the application tries to startup, when doing so, it tries to connect with postgres, which is not yet existing (as the testcontainers are started afterwards).
Thnx in advance.
Update: see answer section for an elaborate answer.
After some deep dive in the Play test suite mechanism, I came up with a workable setup.
Step 1, define your test container suite with an AppProvider:
import com.dimafeng.testcontainers.{Container, ForAllTestContainer}
import org.scalatest.Suite
import org.scalatestplus.play.AppProvider
trait PlayTestContainer extends Suite with AppProvider with ForAllTestContainer {
override val container: Container
}
Step 2, create an abstract PlayTestContainerIntegrationSpec which extends the above trait:
import java.io.File
import com.typesafe.config.ConfigFactory
import org.scalatest.concurrent.{IntegrationPatience, ScalaFutures}
import org.scalatest.{BeforeAndAfterAll, BeforeAndAfterEach, TestData}
import org.scalatestplus.play.PlaySpec
import org.scalatestplus.play.guice.GuiceOneAppPerTest
import play.api.inject.guice.GuiceApplicationBuilder
import play.api.{Application, Configuration, Environment, Mode}
abstract class PlayTestContainerIntegrationSpec
extends PlaySpec
with PlayTestContainer
with GuiceOneAppPerTest
with ScalaFutures
with IntegrationPatience
with BeforeAndAfterEach
with BeforeAndAfterAll {
override def newAppForTest(testData: TestData): Application = application()
def application(): Application =
new GuiceApplicationBuilder()
.in(Environment(new File("."), getClass.getClassLoader, Mode.Test))
.loadConfig(_ => Configuration(ConfigFactory.load("test.conf")))
.build
}
As you can see, we include the "PlayTestContainer" trait and we override the "newAppForTest" function for the construction of a play application.
Step 3, create a specific integration test, extend the above abstract PlayTestContainerIntegrationSpec, and override the container, to your specific need:
class TestIntegrationSpec extends PlayTestContainerIntegrationSpec {
override val container = DockerComposeContainer(ComposeFile(Left(new File("docker-compose.yml"))))
"should test something" in {
assert(true === true)
}
}
Hope this helps.

could not find implicit value for parameter env: com.mohiva.play.silhouette.api.Environment[utils.auth.DefaultEnv]

I'm using a Silhouette v4.0 library with play framework 2.5.
And have been trying to write test code using play specs2.
But, I get the following error with my test class as below.
Error Message
[error] could not find implicit value for parameter env: com.mohiva.play.silhouette.api.Environment[utils.auth.DefaultEnv]
.withAuthenticator[DefaultEnv](identity.loginInfo)
^
Here's the test class
package controllers
import com.google.inject.AbstractModule
import org.joda.time.DateTime
import org.specs2.specification.Scope
import org.specs2.matcher._
import org.specs2.mock._
import play.api.test._
import play.api.libs.json._
import play.api.libs.json.Json
import play.api.libs.json.Reads._
import play.api.libs.functional.syntax._
import play.api.libs.concurrent.Execution.Implicits._
import play.api.libs.mailer.{ MailerClient, Email }
import play.api.inject.guice.GuiceApplicationBuilder
import play.api.inject.bind
import com.mohiva.play.silhouette.test._
import com.mohiva.play.silhouette.api._
import com.mohiva.play.silhouette.api.repositories.AuthInfoRepository
import com.mohiva.play.silhouette.api.util._
import com.mohiva.play.silhouette.impl.providers._
import net.codingwell.scalaguice.ScalaModule
import utils.auth.DefaultEnv
class TestControllerSpec extends PlaySpecification with Mockito {
"case" in new Context {
new WithApplication(application) {
val request = FakeRequest(POST, "/api/test")
.withAuthenticator[DefaultEnv](identity.loginInfo) // <-
val result = route(app, request).get
status(result) must be equalTo OK
}
}
trait Context extends Scope {
val identity = User(
loginInfo = LoginInfo(..)
..
)
implicit val env = FakeEnvironment[DefaultEnv](Seq(identity.loginInfo -> identity))
class FakeModule extends AbstractModule with ScalaModule {
def configure() = {
bind[Environment[DefaultEnv]].toInstance(env)
}
}
lazy val application = new GuiceApplicationBuilder()
.overrides(new FakeModule)
.build
}
}
There are some other test classes similar to this class are properly able to compile and execute.
It's kind of implicit problem with scope..
Therefore, I tried to import all the same as another test class which's able to compile properly. But, still unable to compile.
Missing some import?
As the compiler states, you're missing an implicit value. Use the following, which is modeled after one of Silhouette's specs:
class TestControllerSpec extends PlaySpecification with Mockito {
"the POST request" should {
"return an OK response" in new Context {
new WithApplication(application) {
val identity = User(LoginInfo(...))
implicit val env = FakeEnvironment[DefaultEnv](Seq(identity.loginInfo -> identity))
val request = FakeRequest(POST, "/api/test")
.withAuthenticator(identity.loginInfo)
val result = route(app, request).get
status(result) must be equalTo OK
}
}
}
trait Context extends Scope {
...
}
}

Play Framework Dependency Injection error

This is my code:
package controllers
import javax.inject.Inject
import scala.concurrent.Future
import play.api.Logger
import play.api.mvc.{ Action, Controller }
import play.api.libs.concurrent.Execution.Implicits.defaultContext
import play.api.libs.functional.syntax._
import play.api.libs.json._
// Reactive Mongo imports
import reactivemongo.api.Cursor
import reactivemongo.api.ReadPreference
import play.modules.reactivemongo.{ // ReactiveMongo Play2 plugin
MongoController,
ReactiveMongoApi,
ReactiveMongoComponents
}
// BSON-JSON conversions/collection
import reactivemongo.play.json._
import play.modules.reactivemongo.json.collection._
/*
* Example using ReactiveMongo + Play JSON library.
*
* There are two approaches demonstrated in this controller:
* - using JsObjects directly
* - using case classes that can be turned into JSON using Reads and Writes.
*
* This controller uses JsObjects directly.
*
* Instead of using the default Collection implementation (which interacts with
* BSON structures + BSONReader/BSONWriter), we use a specialized
* implementation that works with JsObject + Reads/Writes.
*
* Of course, you can still use the default Collection implementation
* (BSONCollection.) See ReactiveMongo examples to learn how to use it.
*/
class Application #Inject() (val reactiveMongoApi: ReactiveMongoApi)
extends Controller with MongoController with ReactiveMongoComponents {
def collection: Future[JSONCollection] =
database.map(_.collection[JSONCollection]("Persons"))
def index = Action { Ok("works") }
def create(name: String, age: Int) = Action.async {
val json = Json.obj(
"name" -> name,
"age" -> age,
"created" -> new java.util.Date().getTime())
collection.flatMap(_.insert(json)).map(lastError =>
Ok("Mongo LastError: %s".format(lastError)))
}
}
I´ve an error that said can´t find database value (database is a member of ReactiveMongoApi Trait) so I guess there is something wrong with dependency injection. I added also this line to the build sbt:
adding routesGenerator := InjectedRoutesGenerator
Any ideas? thank you!
You need to refer to the injected API. That is, replace database with reactiveMongoApi.database:
class Application #Inject() (val reactiveMongoApi: ReactiveMongoApi)
extends Controller with MongoController with ReactiveMongoComponents {
def collection: Future[JSONCollection] =
reactiveMongoApi.database.map(_.collection[JSONCollection]("Persons"))
...
}

Play 2.4 scala I am facing issues getting messages implicit in my code

I am trying to migrate my app from 2.3 to 2.4.
In our code base we have used Messages extensively, so any way to remove that will also help.
Currently our code is like this
class MyController #Inject()
(val messagesApi: MessagesApi) extends Controller with I18nSupport{
def methodA() = {
new MyControllerService.doSomething()
}
}
class MyControllerService{
def doSomething()(implicit messages:Messages){
messages(any_key)
}
}
When compiling this code i am getting Error:(31, 84) Play 2 Compiler: could not find implicit value for parameter messages: play.api.i18n.Messages compile time error message.
Please help to resolve this issue, any suggestions to improve this kind of problem in better way is most welcome.
Do it in this way :
class MyController #Inject()
(val messagesApi: MessagesApi) extends Controller with I18nSupport{
def methodA() = { request =>
implicit val messages = messageApi.prefered(request)
new MyControllerService.doSomething()
}
}
class MyControllerService{
def doSomething()(implicit messages:Messages){
messages(any_key)
}
}
or you can pass created messages object directly in this way:
new MyControllerService.doSomething()(messages)
You need to have an implicit request in your Action and the imports for "inject" like so:
package controllers
import javax.inject.Inject
import javax.inject._
import play.api.i18n.{ I18nSupport, MessagesApi, Messages, Lang }
import play.api._
import play.api.mvc._
class Application #Inject() (val messagesApi: MessagesApi) extends Controller with I18nSupport {
def home() = Action { implicit request =>
Ok(views.html.home()).as(HTML)
}
}
in addition, you need to enable the injected router in your build.sbt:
routesGenerator := InjectedRoutesGenerator