Following this answer: https://stackoverflow.com/a/30806548/4496364
I use Play's ExecutionContext in my project.
Recently I needed to use Mockito to test some services in Play.
So, this is simplified version of it:
import scala.concurrent.{ Future, ExecutionContext }
import play.api.libs.concurrent.Execution.Implicits.defaultContext
case class Model(id: Int, name: String)
trait DAO {
def findAll(implicit ec: ExecutionContext): Future[List[Model]]
}
class Service(dao: DAO) {
def findAll: Future[List[Model]] = dao.findAll
}
Test:
import play.api.libs.concurrent.Execution.Implicits.defaultContext
// doesn't work when different ExecutionContext
// import scala.concurrent.ExecutionContext.Implicits.global
class FuturesTest extends PlaySpec with MockitoSugar with ScalaFutures {
"Service" should {
"return all future data" in {
val mockModel = Model(1, "name")
val mockDAO = mock[DAO]
when(mockDAO.findAll) thenReturn Future.successful(List(mockModel))
val service = new Service(mockDAO)
val futureData = service.findAll
whenReady(futureData) { data =>
data.map(_.name) must contain(mockModel.name)
}
}
}
}
Note the comment in test, i get a NullPointException when calling dao.findAll in the Service. At first I thought that Mockito can't handle Scala's Futures but I figured out that the ExecutionContext is the problem. Since I'm not a concurrency expert, can someone please explain why does this happen?
In case someone is looking, the answer was obvious...
import org.mockito.Matchers.any
..
mockDAO.findAll(any[ExecutionContext])
I wasn't familiar with how Mockito works, or with Scala implicits.
When you don't pass any[ExecutionContext] Scala will fill it with the implicit one from the test.
Related
I would like to use Monix Observable with Doobie (fs2) stream, but can't seem to get it working properly. Without streaming, my test app exits just fine but after using streaming, my TaskApp seems to hang on shutdown and can't figure out why.
Here is a minimal example to re-produce the problem:
package example
import java.util.concurrent.Executors
import doobie.implicits._
import cats.effect.{Blocker, ContextShift, ExitCode, Resource}
import doobie.hikari.HikariTransactor
import monix.eval.{Task, TaskApp}
import com.typesafe.scalalogging.StrictLogging
import fs2.interop.reactivestreams._
import monix.reactive.Observable
import scala.concurrent.ExecutionContext
object Hello extends TaskApp with StrictLogging {
private def resources()(implicit contextShift: ContextShift[Task]): Resource[Task, Resources] = {
for {
transactor <- Database.transactor("org.postgresql.Driver", "jdbc:postgresql://localhost/fubar", "fubar", "fubar")
} yield Resources(transactor)
}
def run(args: List[String]): Task[ExitCode] = resources().use(task)
.flatMap(_ => Task { println("All Done!") })
.flatMap(_ => Task(ExitCode.Success))
def task(resources: Resources): Task[Unit] = {
val publisher =
sql"""select id from message;"""
.query[(Long)]
.stream
.transact(resources.transactor)
.toUnicastPublisher()
Observable.fromReactivePublisher(publisher)
.foreachL(id => logger.info(id.toString))
}
}
case class Resources(transactor: HikariTransactor[Task])
object Database {
val ecBlocking = ExecutionContext.fromExecutor(Executors.newFixedThreadPool(8))
def transactor(dbDriver: String, dbUrl: String, dbUser: String, dbPassword: String)(implicit contextShift: ContextShift[Task]): Resource[Task, HikariTransactor[Task]] = {
HikariTransactor.newHikariTransactor[Task](dbDriver, dbUrl, dbUser, dbPassword, ecBlocking, Blocker.liftExecutionContext(ecBlocking))
}
}
I have converted fs2 stream to Monix observable according to Monix documentation: https://monix.io/docs/current/reactive/observable.html#fs2
Do I need to somehow close the fs2 stream or the Observable to get the application exit cleanly?
Appreciate any tips to get this working or tips how to properly debug this.
The problem was that ExecutionContext needs to be shutdown. See the authors' answer here.
Correct usage can been seen in the documentation.
I try to upgrade a Scala/Play project to Play 2.7, Scala 2.12.11, Specs2 4.5.1.
In the project there is the following Specs2 test that I cannot understand in the sense of its Specs2 specification structure (could be that the Specs2 API changed a lot since the test was written).
When I looked at the structure of specifications in the current API, I could not see any example of is method combined together with should.
What was it supposed to mean?
How can I rewrite such a specification in the current Specs2 API?
I also noticed that the test code used import org.specs2.mutable.Specification instead of import org.specs2.Specification which is supposed to be used when using the is method.
And it uses def is(implicit ee: ExecutionEnv), instead of def is.
Here is the old test:
package services
import org.specs2.concurrent.ExecutionEnv
import org.specs2.mutable.Specification
import org.specs2.specification.mutable.ExecutionEnvironment
import play.api.inject.guice.GuiceApplicationBuilder
import play.api.test.WithApplication
import play.modules.reactivemongo._
import scala.concurrent.duration._
class StatisticsServiceSpec() extends Specification with ExecutionEnvironment {
def is(implicit ee: ExecutionEnv) = {
"The StatisticsService" should {
"compute and publish statistics" in new WithApplication() {
val repository = new MongoStatisticsRepository(configuredAppBuilder.injector.instanceOf[ReactiveMongoApi])
val wsTwitterService = new WSTwitterService
val service = new DefaultStatisticsService(repository, wsTwitterService)
val f = service.createUserStatistics("elmanu")
f must beEqualTo(()).await(retries = 0, timeout = 5.seconds)
}
}
def configuredAppBuilder = {
import scala.collection.JavaConversions.iterableAsScalaIterable
val env = play.api.Environment.simple(mode = play.api.Mode.Test)
val config = play.api.Configuration.load(env)
val modules = config.getStringList("play.modules.enabled").fold(
List.empty[String])(l => iterableAsScalaIterable(l).toList)
new GuiceApplicationBuilder().
configure("play.modules.enabled" -> (modules :+
"play.modules.reactivemongo.ReactiveMongoModule")).build
}
}
}
To simplify the code down to the actual Specs2 API, I think it could be reduced to something like this:
package services
import org.specs2.concurrent.ExecutionEnv
import org.specs2.mutable.Specification
import scala.concurrent.Future
import play.api.test.WithApplication
import scala.concurrent.duration._
class StatisticsServiceSpec(implicit ee: ExecutionEnv) extends Specification /* with ExecutionEnvironment */ {
def is(implicit ee: ExecutionEnv) = {
"The StatisticsService" should {
"compute and publish statistics" in new WithApplication() {
val f = Future(1)
f must beEqualTo(1).await(retries = 0, timeout = 5.seconds)
}
}
}
}
Pay attention that I removed the ExecutionEnvironment trait, since it seems to have been removed from the library.
Now, the code finally compiles, but when I try to run the test, there are no errors, but no test is actually run: the output is Empty test suite.
The new specification should be
package services
import org.specs2.concurrent.ExecutionEnv
import org.specs2.mutable.Specification
import scala.concurrent.Future
import play.api.test.WithApplication
import scala.concurrent.duration._
class StatisticsServiceSpec(implicit ee: ExecutionEnv) extends Specification {
"The StatisticsService" should {
"compute and publish statistics" in new WithApplication() {
val f = Future(1)
f must beEqualTo(1).await(retries = 0, timeout = 5.seconds)
}
}
}
The ExecutionEnv is now really supposed to be retrieved as a specification member directly (with an implicit to be make it available to the await method).
is is not necessary in a "mutable" specification. is is the function in a Specification where you declare all the "Fragments" of your specification (a Fragment is a Description + an Execution). In a mutable specification this function is automatically populated from the fact that you trigger method calls directly in the body of the class when the specification is instantiated. The fragments created by should and in are collected in a mutable variable, hence the name "mutable specification".
If you define def is(implicit ee: ExecutionEnv), this is like defining another, valid, is definition that specs2 doesn't know about, while not creating anything for the def is: Fragments method. That's why you end up with an empty specification.
Hello I'm writing scala code to pull the data from API.
Data is paginated, so I'm pulling a data sequentially.
Now, I'm looking a solution to pulling multiple page parallel and stuck to create WSClient programatically instead of Inject.
Anyone have a solution to create WSClient ?
I found a AhcWSClient(), but it required to implicitly import actor system.
When you cannot Inject one as suggested in the other answer, you can create a Standalone WS client using:
import akka.actor.ActorSystem
import akka.stream.ActorMaterializer
import play.api.libs.ws._
import play.api.libs.ws.ahc.StandaloneAhcWSClient
implicit val system = ActorSystem()
implicit val materializer = ActorMaterializer()
val ws = StandaloneAhcWSClient()
No need to reinvent the wheel here. And I'm not sure why you say you can't inject a WSClient. If you can inject a WSClient, then you could do something like this to run the requests in parallel:
class MyClient #Inject() (wsClient: WSClient)(implicit ec: ExecutionContext) {
def getSomething(urls: Vector[String]): Future[Something] = {
val futures = urls.par.map { url =>
wsClient.url(url).get()
}
Future.sequence(futures).map { responses =>
//process responses here. You might want to fold them together
}
}
}
Hey i want to build some small Funsuite test for akka actor application but after combining Testkit with FunSuiteLike i cant call th test anymore.
Somebody an idea why this is happening? is Testkit and funsuite not compatible?
import org.scalatest.{FunSuiteLike, BeforeAndAfterAll}
import akka.testkit.{ImplicitSender, TestKit, TestActorRef}
import akka.actor.{ActorSystem}
class ActorSynchroTest(_system: ActorSystem) extends TestKit(_system) with FunSuiteLike with BeforeAndAfterAll with ImplicitSender{
val actorRef = TestActorRef(new EbTreeDatabase[Int])
val actor = actorRef.underlyingActor
//override def afterAll = TestKit.shutdownActorSystem( system )
test("EbTreeDatabase InsertNewObject is invoked"){
val idList = List(1024L,1025L,1026L,1032L,1033L,1045L,1312L,1800L)
idList.
foreach(x => actorRef ! EbTreeDataObject[Int](x,x,1,None,null))
var cursor:Long = actor.uIdTree.firstKey()
var actorItems:List[Long] = List(cursor)
while(cursor!=actor.uIdTree.lastKey()){
cursor = actor.uIdTree.next(cursor)
cursor :: actorItems
}
assert(idList.diff(actorItems) == List())
}
}
The intelliJ idea test enviroment says:
One or more requested classes are not Suites: model.ActorSynchroTest
class ActorSynchroTest extends TestKit(ActorSystem("ActorSynchroTest",ConfigFactory.parseString(ActorSynchroTest.config)))
with DefaultTimeout with ImplicitSender
with FunSuiteLike with Matchers with BeforeAndAfterAll {
...
}
object ActorSynchroTest {
// Define your test specific configuration here
val config = """
akka {
loglevel = "WARNING"
}
"""
}
Different initialization of the testkit worked in the end before the standard config was used which didn't fit
MyService.scala:33: could not find implicit value for parameter eh: spray.routing.ExceptionHandler
I have run into a "missing implicit" compilation error using Akka, in spray.io code that makes an http call to a separate back-end server, as part of responding to an http get. The code needs to import quite a lot of Spray and Akka libraries, so it's a bit hard figuring whether there may be some library conflicts causing this, and I'd rather figure how to logically trace this sort of problem for this and other cases.
The missing implicit is encountered on calling runRoute(myRoute)
Here's the code:
import spray.routing._
import akka.actor.Actor
import akka.actor.ActorSystem
import spray.http._
import MediaTypes._
import akka.io.IO
import spray.httpx.RequestBuilding._
import scala.concurrent.Future
import spray.can.Http
import spray.http._
import akka.util.Timeout
import HttpMethods._
import akka.pattern.ask
import akka.event.Logging
import scala.concurrent.duration._
// we don't implement our route structure directly in the service actor because
// we want to be able to test it independently, without having to spin up an actor
class MyServiceActor extends Actor with MyService with akka.actor.ActorLogging {
log.info("Starting")
// the HttpService trait defines only one abstract member, which
// connects the services environment to the enclosing actor or test
def actorRefFactory = context
// this actor only runs our route, but you could add
// other things here, like request stream processing
// or timeout handling
def receive = runRoute(myRoute)
}
// this trait defines our service behavior independently from the service actor
trait MyService extends HttpService {
implicit val system: ActorSystem = ActorSystem()
implicit val timeout: Timeout = Timeout(15.seconds)
import system.dispatcher // implicit execution context
//val logger = context.actorSelection("/user/logger")
val logger = actorRefFactory.actorSelection("../logger")
val myRoute =
{
def forward(): String = {
logger ! Log("forwarding to backend")
val response: Future[HttpResponse] =
(IO(Http) ? Get("http:3080//localhost/backend")).mapTo[HttpResponse]
"<html><body><h1>api response after backend processing</h1></body></html>"
}
path("") {
get {
respondWithMediaType(`text/html`) { // XML is marshalled to `text/xml` by default, so we simply override here
complete(forward)
}
}
}
}
}
I am wondering what's the best way to solve this, hopefully providing insight into how to solve similar problems with implicits being missing, as they are somehow inherently not straightforward to track down.
EDIT: when trying to directly pass implicits as in #christian's answer below, I get:
MyService.scala:35: ambiguous implicit values:
both value context in trait Actor of type => akka.actor.ActorContext
and value system in trait MyService of type => akka.actor.ActorSystem
match expected type akka.actor.ActorRefFactory
RoutingSettings.default, LoggingContext.fromActorRefFactory)
^
Not quite sure why being specific as in #christian's answer leaves room for ambiguity for the compiler...
I ran into the same "could not find implicit value for parameter eh: spray.routing.ExceptionHandler" error earlier today. I tried #Christian's approach but saw a few "implicit values for xxx" creeping up. After scouting the error message a little I found adding implicit val system = context.system to the actor that runRoute solved the problem.
runRoute expects a few implicits. You are missing an import:
import spray.routing.RejectionHandler.Default
Update:
I think we also did have some problems with runRoute because we are supplying the implicit parameters explicitly:
runRoute(route)(ExceptionHandler.default, RejectionHandler.Default, context,
RoutingSettings.default, LoggingContext.fromActorRefFactory)
Update2:
To fix the last error, remove the creation of the ActorSystem (in MyService you get the actor system from MyServiceActor - therefore you have to use a self type annotation). This compiles:
import akka.actor.Actor
import akka.io.IO
import spray.httpx.RequestBuilding._
import spray.http.MediaTypes._
import spray.routing.{RoutingSettings, RejectionHandler, ExceptionHandler, HttpService}
import spray.util.LoggingContext
import scala.concurrent.Future
import spray.can.Http
import spray.http._
import akka.util.Timeout
import HttpMethods._
import akka.pattern.ask
import akka.event.Logging
import scala.concurrent.duration._
// we don't implement our route structure directly in the service actor because
// we want to be able to test it independently, without having to spin up an actor
class MyServiceActor extends Actor with MyService with akka.actor.ActorLogging {
log.info("Starting")
// the HttpService trait defines only one abstract member, which
// connects the services environment to the enclosing actor or test
implicit def actorRefFactory = context
// this actor only runs our route, but you could add
// other things here, like request stream processing
// or timeout handling
def receive = runRoute(myRoute)(ExceptionHandler.default, RejectionHandler.Default, context,
RoutingSettings.default, LoggingContext.fromActorRefFactory)
}
// this trait defines our service behavior independently from the service actor
trait MyService extends HttpService { this: MyServiceActor =>
implicit val timeout: Timeout = Timeout(15.seconds)
implicit val system = context.system
//val logger = context.actorSelection("/user/logger")
val logger = actorRefFactory.actorSelection("../logger")
val myRoute =
{
def forward(): String = {
//logger ! Log("forwarding to backend")
val response: Future[HttpResponse] =
(IO(Http) ? Get("http:3080//localhost/backend")).mapTo[HttpResponse]
"<html><body><h1>api response after backend processing</h1></body></html>"
}
path("") {
get {
respondWithMediaType(`text/html`) { // XML is marshalled to `text/xml` by default, so we simply override here
complete(forward)
}
}
}
}
}