How to avoid duplication of mocked functions signatures in scalamock? - scala

I'm using scalamock to mock this class:
class HttpService {
def post[In, Out]
(url: String, payload: In)
(implicit encoder: Encoder[In], decoder: Decoder[Out])
: Future[Out] = ...
...
}
...so my test class has a mock used like this:
val httpService = mock[HttpService]
(httpService.post[FormattedMessage, Unit](_ : String, _ : FormattedMessage) (_ : Encoder[FormattedMessage], _: Decoder[Unit]))
.expects("http://example.com/whatever",*, *, *)
.returning(Future.successful(()))
Apparently I have to write the whole mock function signature. If I only put the underscores in the signature, without the corresponding types, I get errors like this one:
[error] missing parameter type for expanded function ((x$1: <error>, x$2, x$3, x$4) => httpService.post[FormattedMessage, Unit](x$1, x$2)(x$3, x$4))
[error] (httpService.post[FormattedMessage, Unit](_, _) (_, _))
^
What I don't like about this code is that the mock expectation is used in several places in the tests and this ugly signature is repeated all over the place but with different In/Out type parameters and expectations.
So I thought I would write a class
class HttpServiceMock extends MockFactory {
val instance = mock[HttpService]
def post[In, Out] = instance.post[In, Out](_ : String, _ : In) (_ : Encoder[In], _: Decoder[Out])
}
...and use it like this:
val httpService = new HttpServiceMock()
...
httpService.post[FormattedMessage, Unit]
.expects("http://example.com/whatever",*, *, *)
.returning(Future.successful(()))
...which compiles fine but when I run the tests I get the following error:
java.lang.NoSuchMethodException: com.myapp.test.tools.HttpServiceMock.mock$post$0()
at java.lang.Class.getMethod(Class.java:1786)
at com.myapp.controllers.SlackControllerSpec.$anonfun$new$3(SlackControllerSpec.scala:160)
at org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85)
at org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83)
at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
at org.scalatest.Transformer.apply(Transformer.scala:22)
at org.scalatest.Transformer.apply(Transformer.scala:20)
at org.scalatest.WordSpecLike$$anon$1.apply(WordSpecLike.scala:1078)
at org.scalatest.TestSuite.withFixture(TestSuite.scala:196)
at org.scalatest.TestSuite.withFixture$(TestSuite.scala:195)
How can I fix this error? Are there other ways to avoid the re-writing of the mocked function signature over and over again?
UPDATE:
In the end the mock looks like this:
trait HttpServiceMock extends MockFactory {
object httpService {
val instance = mock[HttpService]
def post[In, Out] = toMockFunction4(instance.post[In, Out](_: String, _: In)(_: Encoder[In], _: Decoder[Out]))
}
}

You can use the below code:
trait HttpMockSupport {
this: MockFactory =>
val httpService = mock[HttpService]
def prettyPost[In, Out]: MockFunction4[String, In, Encoder[In], Decoder[Out], Future[Out]] = {
toMockFunction4(httpService.post[In, Out](_: String, _: In)(_: Encoder[In], _: Decoder[Out]))
}
}
class AClassThatNeedsHttpServiceMocking extends FreeSpec with Matchers with MockFactory with HttpMockSupport {
"HttpService should post" in {
val url = "http://localhost/1"
val input = "input"
implicit val encoder: Encoder[String] = new Encoder[String] {}
implicit val decoder: Decoder[String] = new Decoder[String] {}
prettyPost[String, String]
.expects(url, input, encoder, decoder)
.returns(Future.successful("result"))
httpService.post(url, input)
}
}
It puts the common mocking in a trait that can be extended in all the places that needs to mock HttpService and just call the non-ugly method :)
Update 1:
Updated it to accept the expected parameters.
Update 2:
Updated the prettyPost method to be generic so that we can set any kind of expectations.
Scalamock expects a MockFunctionX. So, in your case, all you have to do is to convert the ugly function to a pretty function and then convert it to a MockFunctionX.

Don't use Scalamock, make HttpService a trait and implement the trait directly to mock whatever you need. E.g. (you can paste this in the Scala REPL, but remember to press Enter and Ctrl+D at the end):
:rese
:pa
import scala.concurrent.Future
trait Encoder[A]
trait Decoder[A]
// HttpService.scala
trait HttpService {
def post[In: Encoder, Out: Decoder](
url: String, payload: In): Future[Out]
}
object HttpService extends HttpService {
override def post[In: Encoder, Out: Decoder](
url: String,
payload: In):
Future[Out] = ???
}
// HttpServiceSpec.scala
class Mock[Out](result: Future[Out]) extends HttpService {
override def post[In: Encoder, Out: Decoder](
url: String,
payload: In):
Future[Out] =
// This is fine because it's a mock.
result.asInstanceOf[Future[Out]]
}

Related

Implicit search inside macro expansion fails

Consider a trait that performs "encoding" of arbitrary objects:
trait Encoder[R] {
def encode(r: R): Array[Byte]
}
Assuming encoding of primitive types is known and custom types can be encoded by defining up a "serializer":
trait Serializer[T] {
def serialize(r: T): Array[Byte]
}
we can implement a macro for case class encoding by simply looping the fields and looking up type serializers implicitly. Here's a dummy implementation that looks up the serializer for R itself (in reality we look up serializers for case class field types):
object Encoder {
implicit def apply[R <: Product]: Encoder[R] = macro applyImpl[R]
def applyImpl[R: c.WeakTypeTag](c: blackbox.Context): c.Expr[Encoder[R]] = {
import c.universe._
c.Expr[Encoder[R]](q"""
new ${weakTypeOf[Encoder[R]]} {
override def encode(r: ${weakTypeOf[R]}): Array[Byte] =
implicitly[_root_.Serializer[${weakTypeOf[R]}]].serialize(r)
}
""")
}
}
Now define a base "processor":
abstract class BaseProcessor[R: Encoder] {
def process(r: R): Unit = {
println(implicitly[Encoder[R]].encode(r).length)
}
}
And try to use it:
case class Record(i: Int)
object Serializers {
implicit def recordSerializer: Serializer[Record] =
(r: Record) => Array.emptyByteArray
}
import Serializers._
class Processor extends BaseProcessor[Record]
This fails to compile with:
// [error] Loader.scala:10:22: could not find implicit value for parameter e: Serializer[Record]
// [error] class Processor extends BaseProcessor[Record]
// [error] ^
// [error] one error found
However the following do compile:
class Processor extends BaseProcessor[Record]()(Encoder[Record]) // Compiles!
object x { class Processor extends BaseProcessor[Record] } // Compiles!
I can't really understand why this happens, looks like it has something to do with the Processor definition being a top level definition, since as soon as I move it inside a class/object everything works as expected. Here's one more example that fails to compile:
object x {
import Serializers._ // moving the import here also makes it NOT compile
class Processor extends BaseProcessor[Record]
}
Why does this happen and is there any way to make it work?
To make it work you can try one of the following:
1) add context bound
implicit def apply[R <: Product : Serializer]: Encoder[R] = macro applyImpl[R]
def applyImpl[R: c.WeakTypeTag](c: blackbox.Context)(serializer: c.Expr[Serializer[R]]): c.Expr[Encoder[R]] = {
import c.universe._
c.Expr[Encoder[R]](q"""
new Encoder[${weakTypeOf[R]}] {
override def encode(r: ${weakTypeOf[R]}): Array[Byte] =
$serializer.serialize(r)
}
""")
}
2) make macro whitebox
3) put implicit instance recordSerializer: Serializer[Record] to the companion object of Record rather than some object Serializers to be imported
4) maybe your example is easier than actual use case but now it seems you don't need macros
implicit def apply[R <: Product : Serializer]: Encoder[R] = new Encoder[R] {
override def encode(r: R): Array[Byte] = implicitly[Serializer[R]].serialize(r)
}

Scala: determine method result type for use in generics

In a third-party library there is a series of request classes, all of which derive from some common base class, which is generic and takes response class as a parameter:
abstract class AbstractRequest[ResponseType] {
…
def execute(): ResponseType
}
class UserList {…}
class UserListRequest extends AbstractRequest[UserList] {…}
class Avatar {…}
class AvatarRequest extends AbstractRequest[Avatar] {…}
…
I want to write some generic method that takes a request instance, executes it several times in some special ways and delegates processing of the responses to a function supplied in arguments:
def specialMultiExecute(request: Req)(responseHandler: Resp => Unit): Unit = …
— to be called like:
val myRequest: UserListRequest = …
specialMultiExecute(myRequest){ userList => … }
The problem is that I need to somehow specify Req and Resp types in the specialMultiExecute declaration. I tried the obvious approach:
def specialMultiExecute[Req <: AbstractRequest[Resp], Resp](request: Req)(responseHandler: Resp => Unit): Unit = …
— but Scala compiler fails to deduct generic argument types (an explicit specification like specialMultiExecute[UserListRequest, UserList](myRequest){ userList => … } is required).
In C++ in such case I could write a template function with a single template parameter Req, while making Resp to be determined as result type of the method Req::execute:
template<typename Req>
void specialMultiExecute(
Req request,
std::function<void (decltype(std::declval<Req>().execute()))> responseHandler
) {…}
//i.e. we use `decltype(std::declval<Req>().execute())` instead of Resp
Is there way to write something similar is Scala?
I mean something like (in Scala-like pseudocode):
def specialMultiExecute[Req <: AbstractRequest](request: Req)(responseHandler: ResultTypeOf(Req#execute) => Unit): Unit = …
It is a limitation of the type inference mechanism.
The simplest way to solve it is to use an implicit evidence that Req is a subtype of AbstractRequest[ResponseType].
Here is an example.
import scala.language.implicitConversions
import scala.reflect.runtime.universe.TypeTag
abstract class AbstractRequest[ResponseType] {
def execute(): ResponseType
}
final case class User(id: Int, name: String)
final case class House(id: Int, price: Int)
class UserListRequest extends AbstractRequest[List[User]] {
override def execute(): List[User] = List(User(id = 3, name = "Sasha"))
override def toString: String = "UserListRequest"
}
final class RequestWrapper[Req, Resp](val request: Req) extends AnyVal {
type ResponseType = Resp
}
implicit def request2wrapper[Req, Resp](request: Req)(implicit ev: Req <:< AbstractRequest[Resp]): RequestWrapper[Req, Resp] =
new RequestWrapper(request)
def specialMultiExecute[Req, Resp](wrapper: RequestWrapper[Req, Resp])
(responseHandler: wrapper.ResponseType => Unit)
(implicit ev: Req <:< AbstractRequest[Resp], TTReq: TypeTag[Req], TTResp: TypeTag[Resp]): Unit = {
val request: Req = wrapper.request
val executionResult: Resp = request.execute()
responseHandler(executionResult)
println(TTReq)
println(TTResp)
println(request)
}
specialMultiExecute(new UserListRequest())(println)
// List(User(3,Sasha))
// TypeTag[UserListRequest]
// TypeTag[List[User]]
// UserListRequest
Reference for <:<.
Reference for "Dependent types".
Edit
Te above code example was modified to allow identification of the concrete Request and Response types being used.

Spray JSON Format and Conversion Error

I have a trait for which I wanted to write Typeclasses for. This trait actually is a contract to do JSON to Case class conversion and vice versa. The definition of the trait is as below:
trait Converter[T] {
def convertFromJson(msg: String): Either[ConverterError, T]
def convertToJson(msg: T): String
}
Now, for one of the case classes that I have, I have defined the implementation like this:
object Converter extends DefaultJsonProtocol {
implicit object DefaultMessageConversions extends Converter[DefaultMessage] {
implicit val json = jsonFormat(DefaultMessage, "timestamp")
def convertFromJson(msg: String): Either[ConverterError, DefaultMessage] = {
try {
Right(msg.parseJson.convertTo[DefaultMessage])
}
catch {
case _: Exception => Left(ConverterError("Shit happens"))
}
}
def convertToJson(msg: DefaultMessage) = {
implicit val writes = Json.writes[DefaultMessage]
Json.toJson(msg).toString
}
}
def apply[T: Converter] : Converter[T] = implicitly
}
But I run into some compiler errors when I tried to build my project. I'm not sure what I did wrong?
[error] /Users/joesan/ingestion/src/main/scala/com/my/project/common/JsonMessageConversion.scala:28: could not find implicit value for evidence parameter of type com.my.project.common.JsonMessageConversion.Converter.JF[org.joda.time.DateTime]
[error] implicit val json = jsonFormat(DefaultMessage, "timestamp")
Here is how my case class look like:
case class DefaultMessage(timestamp: DateTime) extends KafkaMessage {
def this() = this(DateTime.now(DateTimeZone.UTC))
}
Your DefaultMessage uses org.joda.time.DateTime and spray-json does not know how to serialize/deserialize it out of the box.
Therefore you need to define a RootJsonFormat[DateTime] and bring it in implicit scope.
Here is an example implementation.

Implicit conversion not applying

I was trying to workout the classic example of converting arbitrary values into their Json representation and having compile time errors in case conversion is not defined.
So far, I have,
trait Json
trait ConvertableToJson[A] {
def toJson: Json
}
object Json {
case class Str(str: String) extends Json
case class Int(int : Int) extends Json
case class StrToJson(s: String) extends ConvertableToJson[StrToJson] {
override def toJson: Json = Str(s)
}
}
implicit def str2Json(s: String): StrToJson = StrToJson(s)
def toJson[A <: ConvertableToJson[A]](a: A) = a.toJson
println(toJson("some string"))
I expected the above code to work like:
toJson("some string") to fail to compile without the implicit def. Because String <: ConvertableToJson[String] is false.
But then to use, the implicit def and find Str2Json.
Str2Json <: ConvertableToJson[Str2Json] should be true.
However, this doesn't happen and compiler complains:
Error: Inferred type arguments [String] do not conform to method toJson's type parameter bounds [A <: scalaz.ConvertToJson.ConvertableToJson[A]]
println(toJson("dhruv"))
^
It'll be great if someone can help me correct my understanding
So there are two problems with your code. First of all String does not extend ConvertableToJson[String], which is what your last function call is trying to do.
Second case class StrToJson should extend ConvertableToJson[String] not ConvertableToJson[StrToJson].
Then your code be made to compile by using view-bounds <% (see the working example below). This however is a bad idea because view-bounds are being deprecated as a language feature, you should use type classes instead.
trait Json
trait ConvertableToJson[A] {
def toJson: Json
}
object Json {
case class Str(str: String) extends Json
case class Int(int : Int) extends Json
case class StrToJson(s: String) extends ConvertableToJson[String] {
override def toJson: Json = Str(s)
}
}
import Json._
implicit def str2Json(s: String): StrToJson = StrToJson(s)
def toJson[A <% ConvertableToJson[A]](a: A) = a.toJson
println(toJson("some string"))
Using typeclasses
trait Json
trait ConvertableToJson[A] {
// NOTE: this now takes a parameter
def toJson(a: A): Json
}
object Json {
case class Str(str: String) extends Json
case class Int(int : Int) extends Json
}
import Json._
// NOTE: Because toJson takes a parameter the implicit implementation can now be an object
implicit object Str2Json extends ConvertableToJson[String] {
override def toJson(a: String): Json = Str(a)
}
// NOTE: If you want to support the a.toJson syntax this implicit class adds it for all types with an implicit ConvertableToJson
implicit class ConvertableToJsonSyntax[A](a: A)(implicit ev: ConvertableToJson[A]) {
def toJson: Json = ev.toJson(a)
}
// NOTE: Now we use context-bounds instead of view-bounds
def toJson[A : ConvertableToJson](a: A) = a.toJson
// NOTE: we can expand the context-bounds
def toJson2[A](a: A)(implicit ev: ConvertableToJson[A]) = a.toJson
// NOTE: But since we have the type class instance now, we do not need the extra syntax
def toJson3[A](a: A)(implicit ev: ConvertableToJson[A]) = ev.toJson(a)
println(toJson("some string"))

Scala implicit type class dependency injection

I'd like some help sorting out this scenario. I have an Akka actor where I want to inject a dependency, in this case RemoteFetcher, which I would also like mock in my tests. Like so:
main/src/scala/mypackage/Services.scala
package mypackage
import RemoteFetcherFileSystem._
trait RemoteFetcher {
def fetch( path:String ): Future[Stream[String]]
}
class MyRemoteResourceActor extends Actor with ActorLogging {
def fetchRemote( path:String ) = implicitly[RemoteFetcher].fetch( path )
def receive = {
case FetchRemoteResource( path ) => fetchRemote( path ).map( _.foreach( sender ! _ ) )
}
}
For this to work I have an implicit object that I import into the file above. Would look something like this:
implicit object RemoteFetcherFileSystem extends RemoteFetcher {
def fetchRemote( path:String ) = Future[Stream[String]] { ... reading from file system ... }
}
Now in my tests I have TestActor from the akka-testkit. Here I want to instead import my mock dependency:
implicit object RemoteFetcherMock extends RemoteFetcher {
def fetchRemote( path:String ) = Future[Stream[String]] { ... mock implementation ... }
}
My problem is that to compile Services.scala I need to import the implicit object. But how do I go about to shadow/override this in my test-files. The reason I'm not using implicit arguments is that I want to avoid having to modify all my actors constructor arguments.
I when looking around and reading up on the type class dependency injection pattern and I get it to work according to the tutorials, but I don't get it to work when I want to test and override like in my example.
I'm not sure how to do it with implicits, but typically one could inject instead like so:
trait RemoteFetcherComponent {
def remoteFetcher: RemoteFetcher
trait RemoteFetcher {
def fetch(path: String): Future[Stream[String]]
}
}
trait RemoteFetcherFileSystemComponent extends RemoteFetcherComponent {
val remoteFetcher = RemoteFetcherFileSystem
object RemoteFetcherFileSystem extends RemoteFetcher {
def fetch(path: String): Future[Stream[String]] = ???
}
}
class MyRemoteResourceActor extends Actor with ActorLogging with RemoteFetcherFileSystemComponent {
def fetchRemote(path: String) = remoteFetcher.fetch(path)
def receive = {
case FetchRemoteResource(path) => fetchRemote(path).map( _.foreach(sender ! _))
}
}
val myRemoteResourceActor = new MyRemoteResourceActor()
And then a test value would be defined like so:
trait RemoteFetcherMockComponent extends RemoteFetcherComponent {
def remoteFetcher = RemoteFetcherMock
object RemoteFetcherMock extends RemoteFetcher {
def fetch(path: String): Future[Stream[String]] = ???
}
}
val myMockedResourceActor = new MyRemoteResourceActor with RemoteFetcherMockComponent {
override val remoteFetcher = super[RemoteFetcherMockComponent].remoteFetcher
}
The reason you are having an issue with implicits is because the way you're using it is no different from simply using def fetchRemote(path: String) = RemoteFetcherFileSystem.fetch(path). With the import, you've defined the implementation, rather than allowed it to be injected later.
You could also change the implicitly to an implicit parameter:
trait RemoteFetcher {
def fetch(path: String): Future[Stream[String]]
}
object RemoteFetcher {
implicit val fetcher = RemoteFetcherFileSystem
}
class MyRemoteResourceActor extends Actor with ActorLogging {
def fetchRemote(path: String)(implicit remoteFetcher: RemoteFetcher) = remoteFetcher.fetch(path)
def receive = {
case FetchRemoteResource(path) => fetchRemote(path).map( _.foreach(sender ! _))
}
}
Then you could override the implicit that is resolved in the companion object of RemoteFetcher by simply importing RemoteFetcherMock.
See this post for more information about implicit parameter resolution precedence rules.