Unable to pass mocked fixture as an argument in parametrized tests in pytest - pytest

See below, is it even possible to pass a mock fixture (mock_adam, "adam", "0.001", ...) in parametrized tests for reusability purposes?
import pytest
from contextlib import contextmanager
from unittest import mock
from my_module import get_optimizer
#contextmanager
def does_not_raise():
yield
#pytest.fixture(autouse=True)
def mock_adam():
with mock.patch("my_module.optimizers.Adam") as mocker:
yield mocker
#pytest.fixture(autouse=True)
def mock_RMSprop():
with mock.patch("my_module.optimizers.RMSprop") as mocker:
yield mocker
class TestGetOptimizers:
#pytest.mark.parametrize(
"mock_optimizer, optimizer_name, learning_rate, clipnorm, expectation",
[
(mock_adam, "adam", "0.001", "1.1", does_not_raise()),
(mock_RMSprop, "rmsprop", "0.001", "1.1", does_not_raise()),
],
)
def test_get_optimizer(self, mock_optimizer, optimizer_name, learning_rate, clipnorm, expectation):
with expectation:
get_optimizer(
optimizer_name=optimizer_name,
learning_rate=learning_rate,
clipnorm=clipnorm,
)
mock_optimizer.assert_called_once_with(lr=learning_rate, clipnorm=clipnorm)
AttributeError: 'function' object has no attribute 'assert_called_once_with'

To achieve this, you can create a single fixture that would get the path to mock as an indirect parameter, like so:
import pytest
from contextlib import contextmanager
from unittest import mock
from my_module import get_optimizer
#contextmanager
def does_not_raise():
yield
#pytest.fixture
def mock_with_param(request):
with mock.patch(request.param) as mocker:
yield mocker
class TestGetOptimizers:
#pytest.mark.parametrize(
"mock_with_param, optimizer_name, learning_rate, clipnorm, expectation",
[
("my_module.optimizers.Adam", "adam", "0.001", "1.1", does_not_raise()),
("my_module.optimizers.RMSprop", "rmsprop", "0.001", "1.1", does_not_raise()),
], indirect=["mock_with_param"]
)
def test_get_optimizer(self, mock_with_param, optimizer_name, learning_rate, clipnorm, expectation):
with expectation:
get_optimizer(
optimizer_name=optimizer_name,
learning_rate=learning_rate,
clipnorm=clipnorm,
)
mock_with_param.assert_called_once_with(lr=learning_rate, clipnorm=clipnorm)

Related

type mismatch with akka.http.scaladsl.server.Route

I've created a http server with akka http as follows:
import akka.actor.typed.{ActorRef, ActorSystem}
import akka.http.scaladsl.Http
import akka.http.scaladsl.server.Route
import com.sweetsoft.LoggerActor.Log
import akka.actor.typed.scaladsl.adapter._
import akka.http.scaladsl.Http.ServerBinding
import akka.http.scaladsl.model._
import com.sweetsoft._
import akka.http.scaladsl.server.Directives._
import akka.stream.typed.scaladsl.ActorMaterializer
import scala.concurrent.Future
object ProducerActor {
private val route: Option[ActorRef[ProducerMessage]] => Option[ActorRef[Log]] => Route
= store => logger =>
path("producer") {
post {
entity(as[ProducerMessage]) { msg =>
complete(HttpEntity(ContentTypes.`text/html(UTF-8)`, "<h1>Say hello to akka-http</h1>"))
}
}
}
def create[A](store: Option[ActorRef[ProducerMessage]], logger: Option[ActorRef[Log]])
(implicit system: ActorSystem[A])
: Future[ServerBinding] = {
implicit val materializer = ActorMaterializer()
//Please log
Http()(system.toUntyped).bindAndHandle(route(store)(logger), getServerIp, getServerPort)
}
}
The compiler complains:
[error] /home/developer/scala/plugger/src/main/scala/com/sweetsoft/producer/ProducerActor.scala:35:56: type mismatch;
[error] found : akka.http.scaladsl.server.Route
[error] (which expands to) akka.http.scaladsl.server.RequestContext => scala.concurrent.Future[akka.http.scaladsl.server.RouteResult]
[error] required: akka.stream.scaladsl.Flow[akka.http.scaladsl.model.HttpRequest,akka.http.scaladsl.model.HttpResponse,Any]
[error] Http()(system.toUntyped).bindAndHandle(route(store)(logger), getServerIp, getServerPort)
Do I forget to import any libraries?
From the documentation:
Using Route.handlerFlow or Route.asyncHandler a Route can be lifted into a handler Flow or async handler function to be used with a bindAndHandleXXX call from the Core Server API.
Note: There is also an implicit conversion from Route to Flow[HttpRequest, HttpResponse, Unit] defined in the RouteResult companion, which relies on Route.handlerFlow.
Therefore, you have at least three options:
Call Route.handlerFlow:
...bindAndHandle(Route.handlerFlow(route(store)(logger)), ...)
Import the methods in the Route companion object and do the same as above, except now you can drop the explicit reference to the Route object:
import akka.http.scaladsl.server.Route
import akka.http.scaladsl.server.Route._
...bindAndHandle(handlerFlow(route(store)(logger)), ...)
Import akka.http.scaladsl.server.RouteResult._:
import akka.http.scaladsl.server.RouteResult._
...bindAndHandle(route(store)(logger), ...)

Creating functional tests Scala Playframework 2.6 Macwire

I wrote some traits to use it as a base for my functional tests
This file is for creating a DB in memory (H2 + Evolutions)
BlogApiDBTest.scala
package functional.common
import play.api.db.Databases
import play.api.db.evolutions.Evolutions
trait BlogApiDBTest {
implicit val testDatabase = Databases.inMemory(
name = "blog_db",
urlOptions = Map(
"MODE" -> "MYSQL"
),
config = Map(
"logStatements" -> true
)
)
org.h2.engine.Mode.getInstance("MYSQL").convertInsertNullToZero = false
Evolutions.applyEvolutions(testDatabase)
}
Here I am overriding some injected components for testing purposes
BlogApiComponentsTest.scala
package functional.common
import common.BlogApiComponents
import org.scalatestplus.play.components.WithApplicationComponents
import play.api.{BuiltInComponents, Configuration}
trait BlogApiComponentsTest extends WithApplicationComponents with BlogApiDBTest {
override def components: BuiltInComponents = new BlogApiComponents(context) {
override lazy val configuration: Configuration = context.initialConfiguration
override lazy val blogDatabase = testDatabase
}
}
This is the base class for my functional tests
BlogApiOneServerPerTestWithComponents.scala
package functional.common
import org.scalatestplus.play.PlaySpec
import org.scalatestplus.play.components.{OneServerPerTestWithComponents}
trait BlogApiOneServerPerTestWithComponents extends PlaySpec with OneServerPerTestWithComponents with BlogApiComponentsTest {
}
Finally the test I am trying to execute
PostControllerSpec.scala
package functional.controllers
import functional.common.BlogApiOneServerPerTestWithComponents
import org.scalatest.concurrent.{IntegrationPatience, ScalaFutures}
import play.api.mvc.{Results}
import play.api.test.{FakeRequest, Helpers}
import play.api.test.Helpers.{GET, route}
class PostControllerSpec extends BlogApiOneServerPerTestWithComponents
with Results
with ScalaFutures
with IntegrationPatience {
"Server query should" should {
"provide an Application" in {
val Some(result) = route(app, FakeRequest(GET, "/posts"))
Helpers.contentAsString(result) must be("success!")
}
}
}
Then I get
blog-api/test/functional/controllers/PostControllerSpec.scala:18:31: Cannot write an instance of play.api.mvc.AnyContentAsEmpty.type to HTTP response. Try to define a Writeable[play.api.mvc.AnyContentAsEmpty.type]
Here is the code
Adding the following import should make it work:
import play.api.test.Helpers._
Looking at the signature of route
def route[T](app: Application, req: Request[T])(implicit w: Writeable[T]): Option[Future[Result]]
we see it expects an implicit w: Writeable[T]. The above import will provide it via Writables

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 {
...
}
}

How do I verify mockito calls in asynchronous methods

I'm writing a highly asynchronous bit of code and I'm having problems testing it using Specs2 and Mockito. The problem is that the matchers are executed before the asynchronous code executes. I see that specs2 has await and eventually helpers - they look promising but I'm not sure how to use them.
Below is a stripped down example that illustrates the problem
SUT
package example.jt
import scala.concurrent._
import ExecutionContext.Implicits.global
import scala.util.{Try, Success, Failure}
trait Service {
def foo
def bar
def baz
}
class AnotherTest(svc: Service) {
def method(fail: Boolean) {
svc.baz
future {
Thread.sleep(3000)
pvt(fail) onComplete {
case Success(_) => svc.foo
case Failure(ex) => svc.bar
}
}
}
private def pvt(fail: Boolean):Future[Unit] = {
val p = Promise[Unit]
future {
Thread.sleep(2000)
if (fail) p failure (new RuntimeException("Failure"))
else p success ()
}
return p.future
}
}
Specs2 Test
package example.jt.test
import example.jt._
import org.specs2.specification._
import org.specs2.mutable._
import org.specs2.specification._
import org.specs2.mutable._
import org.specs2.mock._
class TestPromise extends Specification with Mockito {
"mocks in promises" should {
"Verify foo" in {
val svc = mock[Service]
val sut = new AnotherTest(svc)
sut.method(false)
there was one(svc).baz
there was one(svc).foo
there was no(svc).bar
}
"Verify bar" in {
val svc = mock[Service]
val sut = new AnotherTest(svc)
sut.method(true)
there was one(svc).baz
there was one(svc).bar
there was no(svc).foo
}
}
}
You simply need to wait on your future calls. Either by using Await directly:
import scala.concurrent._
import scala.concurrent.duration._
Await(sut.method(false), 10 seconds)
or by using .await on a matcher (look for await in the matchers guide):
sut.method(false) must not(throwAn[Exception]).await

Scalatest 2.10 with akka.TestKit, weird compilier error

I'm using the scala IDE for development. I have a few actors which I'm testing out. I wrote one scala test suite with the following definition and didn't have any problems:
import org.scalatest._
import akka.testkit._
import akka.actor.ActorSystem
import org.scalatest.BeforeAndAfterAll
import org.scalatest._
import scala.concurrent.duration._
import akka.actor.Props
import filters._
class ReaderSourceTest( _system: ActorSystem ) extends TestKit( _system ) with FunSuiteLike with BeforeAndAfterAll with ImplicitSender {
import ReaderSource._
//Must have a zero argument constructor
def this() = this( ActorSystem( "ReaderSourceSuite" ) )
override def afterAll = TestKit.shutdownActorSystem( system )
test( "Reader should be alive as an actor" ) {
val reader = system.actorOf( Props( classOf[ ReaderSource ], "dummy/file/name" ), "tstReaderA" )
reader ! Ping( "Hello" )
expectMsg( Pong( "Hello" ) )
}
}
I then created another test file to test another actor which goes like this:
import socketclient._
import org.scalatest._
import akka.testkit._
import akka.actor.ActorSystem
import org.scalatest.BeforeAndAfterAll
import scala.concurrent.duration._
import akka.actor.Props
import org.scalatest.fixture.FunSuiteLike
import java.net.InetAddress
import org.kdawg.CommProtocol.CommMessages._
import org.kdawg.CommProtocol.CommMessages
class NetworkTest( _system: ActorSystem ) extends TestKit( _system ) with FunSuiteLike with BeforeAndAfterAll with ImplicitSender
{
import NetworkTalker._
def this() = this( ActorSystem( "NetworkTalkerTest") )
override def afterAll = TestKit.shutdownActorSystem( system )
test( "Can Send a Packet" )
{
val net = system.actorOf( NetworkTalker.props("10.1.0.5", 31000), "TestA" )
val pktBuilder = CommMessage.newBuilder
pktBuilder.setType( MessageType.STATUS_REQUEST )
pktBuilder.setStatusRequest( CommProtocol.CommandsProtos.StatusRequest.newBuilder() )
val pkt = pktBuilder.build
net ! PktSend(1, pkt)
expectMsg( PktSent(1) )
}
}
I keep getting the following error on the last line of the above class
Multiple markers at this line
- type mismatch; found : org.kdawg.socketclient.NetworkTalker.PktSent required: NetworkTalkerTest.this.FixtureParam =>
Any
- type mismatch; found : org.kdawg.socketclient.NetworkTalker.PktSent required: NetworkTalkerTest.this.FixtureParam =>
Can anyone help me figure this out ?
Changing imports from
import org.scalatest.fixture.FunSuiteLike
to
import org.scalatest.FunSuiteLike
worked