mocking generic method using Mockito and Scala - scala

I'm trying to write a test for the following function in Finatra HttpClient.
def executeJson[T: Manifest](
request: Request,
expectedStatus: Status = Status.Ok): Future[T] = {...}
According to another question answered on StackOverflow. mocking generic scala method in mockito. This is a shorthand for:
def executeJson[T](
request: Request,
expectedStatus: Status = Status.Ok)
(implicit T: Manifest[T]): Futuren[T] = {...}
So I tried,
verify(httpClientMock, times(1)).executeJson[JiraProject]
(argThat(new RequestMatcher(req)))(Matchers.any())
Unfortunately, it didn't solve my problem. I still got the following error.
Invalid use of argument matchers!
0 matchers expected, 1 recorded:
-> at org.specs.mock.MockitoStubs$class.argThat(Mockito.scala:331)
This exception may occur if matchers are combined with raw values:
//incorrect:
someMethod(anyObject(), "raw String");
When using matchers, all arguments have to be provided by matchers.
For example:
//correct:
someMethod(anyObject(), eq("String by matcher"));
I also tried Matchers.eq(Manifest[JiraProject]), it complains that value Manifest of type scala.reflect.ManifestFactory.type does not take type parameters.
I'm new to Scala and Mockito, is there anything I did wrong or I misunderstood?
Thanks in advance for any help!
Found out the problem! So the executeJson actually takes 3 params- request, expectedStatus, and a Manifest. However, because expectedStatus is an optional, I didn't explicit pass it, that's why it complained. So, the final code should be verify(httpClientMock, times(1)).executeJson[JiraProject](argThat(new RequestMatcher(req)), Matchers.any[Status])(Matchers.any())

Your problem is that you're using equality in the first parameter and matcher for the second one. Try using matchers for all arguments.
But a bigger problem that I feel here is that you're trying to mock 3rd party library - this is something you should avoid. This would also solve your problem. Here's some extra read about it - TDD best practices: don't mock others

Related

Problem with mockito matchers when i run my tests

I'm new with Mockito and I'm dealing with a very strange problem with matchers
def fetchById[T: Format](elasticDetails: ESDetails): F[ESResult[T]]
I have this def for my Elastic search client and the problem start with the generic Format : T that i have there to pass.
.fetchById[JsValue](anyObject[ESDetails])
.returns(IO.pure(ESResult(200, value = Some(fakeResponse)))) ```
org.mockito.exceptions.misusing.InvalidUseOfMatchersException:
Invalid use of argument matchers!
2 matchers expected, 1 recorded:
-> at org.specs2.mock.mockito.MockitoMatchers.anyObject(MockitoMatchers.scala:49)
This exception may occur if matchers are combined with raw values:
//incorrect:
someMethod(anyObject(), "raw String");
When using matchers, all arguments have to be provided by matchers.
For example:
//correct:
someMethod(anyObject(), eq("String by matcher"));```
//This the error for matchers that i'm getting after I run my tests.
You are implicitly passing a real instance of Format[T] alongside the fake Matcher instance of ESDetails. Mockito requires that all arguments be either real instances or Matchers and does not allow you to mix them, as you see from this error message.
The simplest fix will be to turn the implicit argument into a Matcher, e.g.
.fetchById[JsValue](anyObject[ESDetails])(eq(implicitly[Format[T]]))
See also What precisely is a scala evidence parameter
and How to stub a method call with an implicit matcher in Mockito and Scala
As mentioned by Mateusz, you will probably be better off using scalamock than Mockito, as it handles this situation much better as it was designed for Scala.

Scala type inference not working with play json

I am writing an http client and this is my signature:
def post[Req, Resp](json: Req)(implicit r: Reads[Resp], w: Writes[Req]): Future[Resp]
Using play json behind the scenes.
When I use it like this
def create(req: ClusterCreateRequest): Future[ClusterCreateResponse] = endpoint.post(req)
I get the following error
diverging implicit expansion for type play.api.libs.json.Reads[Resp]
The following works
def create(req: ClusterCreateRequest): Future[ClusterCreateResponse] = endpoint.post[ClusterCreateRequest, ClusterCreateResponse](req)
Why is type inference not working as expected? What can I do for this?
diverging implicit expansion for type play.api.libs.json.Reads[Resp]
means that Resp has few JSON serializers that are not shadowed one by another.
It's not possible to pinpoint root cause the issue and say fix X and everything will work from the infrmation given in post.
But you can try to "debug" implicit search. Consider checking the implicit search order:
Where does Scala look for implicits? Enabling implicit parameter expansion in idea might help to check which implicits(Ctrl+Shift+=) cause a clash.
General advice for type class instances - hold them organized and declared, put them to companion object or to specially dedicated object.

can`t bind[SttpBackend[Try, Nothing]]

I want to use sttp library with guice(with scalaguice wrapper) in my app. But seems it is not so easy to correctly bind things like SttpBackend[Try, Nothing]
SttpBackend.scala
Try[_] and Try[AnyRef] show some other errors, but still have no idea how it should be done correctly
the error I got:
kinds of the type arguments (scala.util.Try) do not conform to the expected kinds of the type parameters (type T).
[error] scala.util.Try's type parameters do not match type T's expected parameters:
[error] class Try has one type parameter, but type T has none
[error] bind[SttpBackend[Try, Nothing]].toProvider[SttpBackendProvider]
[error] ` ^
SttpBackendProvider looks like:
def get: SttpBackend[Try, Nothing] = TryHttpURLConnectionBackend(opts)
complete example in scastie
interesting that version scalaguice 4.1.0 show this error, but latest 4.2.2 shows error inside it with converting Nothing to JavaType
I believe you hit two different bugs in the Scala-Guice one of which is not fixed yet (and probably even not submitted yet).
To describe those issues I need a fast intro into how Guice and Scala-Guice work. Essentially what Guice do is have a mapping from type onto the factory method for an object of that type. To support some advanced features types are mapped onto some internal "keys" representation and then for each "key" Guice builds a way to construct a corresponding object. Also it is important that generics in Java are implemented using type erasure. That's why when you write something like:
bind(classOf[SttpBackend[Try, Nothing]]).toProvider(classOf[SttpBackendProvider])
in raw-Guice, the "key" actually becomes something like "com.softwaremill.sttp.SttpBackend". Luckily Guice developers have thought about this issue with generics and introduced TypeLiteral[T] so you can convey the information about generics.
Scala type system is more reach than in Java and it has some better reflection support from the compiler. Scala-Guice exploits it to map Scala-types on those more detailed keys automatically. Unfortunately it doesn't always work perfectly.
The first issue is the result of the facts that the type SttpBackend is defined as
trait SttpBackend[R[_], -S]
so it uses it expects its first parameter to be a type constructor; and that originally Scala-Guice used the scala.reflect.Manifest infrastructure. AFAIU such higher-kind types are not representable as Manifest and this is what the error in your question really says.
Luckily Scala has added a new scala.reflect.runtime.universe.TypeTag infrastructure to tackle this issue in a better and more consistent way and the Scala-Guice migrated to its usage. That's why with the newer version of Scala-Guice the compiler error goes away. Unfortunately there is another bug in the Scala-Guice that makes the code fail in runtime and it is a lack of handling of the Nothing Scala type. You see, the Nothing type is a kind of fake one on the JVM. It is one of the things where the Scala type system is more reach than the Java one. There is no direct mapping for Nothing in the JVM world. Luckily there is no way to create any value of the type Nothing. Unfortunately you still can create a classOf[Nothing]. The Scala-to-JVM compiler handles it by using an artificial scala.runtime.Nothing$. It is not a part of the public API, it is implementation details of specifically Scala over JVM. Anyway this means that the Nothing type needs additional handling when converting into the Guice TypeLiteral and there is none. There is for Any the cousin of Nothing but not for Nothing (see the usage of the anyType in TypeConversions.scala).
So there are really two workarounds:
Use raw Java-based syntax for Guice instead of the nice Scala-Guice one:
bind(new TypeLiteral[SttpBackend[Try, Nothing]]() {})
.toInstance(sttpBackend) // or to whatever
See online demo based on your example.
Patch the TypeConversions.scala in the Scala-Guice as in:
private[scalaguice] object TypeConversions {
private val mirror = runtimeMirror(getClass.getClassLoader)
private val anyType = typeOf[Any]
private val nothingType = typeOf[Nothing] // added
...
def scalaTypeToJavaType(scalaType: ScalaType): JavaType = {
scalaType.dealias match {
case `anyType` => classOf[java.lang.Object]
case `nothingType` => classOf[scala.runtime.Nothing$] //added
...
I tried it locally and it seems to fix your example. I didn't do any extensive tests so it might have broken something else.

using jmock in Scala with type parameterized function

I want to test a function that writes output from in RDD in Scala Spark.
Part of this test is mocking a map on an RDD, using jmock
val customerRdd = mockery.mock(classOf[RDD[Customer]], "rdd1")
val transformedRddToWrite = mockery.mock(classOf[RDD[TransformedCustomer]], "rdd2")
mockery.checking(new Expectations() {{
// ...
oneOf(customerRdd).map(
`with`(Expectations.any(classOf[Customer => TransformedCustomer]))
)
will(Expectations.returnValue(transformedRddToWrite))
// ...
}})
However, whenever I try to run this test, I get the following error:
not all parameters were given explicit matchers: either all parameters must be specified by matchers or all must be specified by values, you cannot mix matchers and values, despite the fact that I have specified matchers for all parameters to .map.
How do I fix this? Can jMock support matching on Scala functional arguments with implicit classtags?
jMock I thought has been abandoned since 2012. But if you like it, then more power to you. One of the issues is that map requires a ClassTag[U] according to the signature :
def map[U: ClassTag](f: T => U): RDD[U] where U is the return type of your function.
I am going to heavily assume that if you were to make this work with a Java mocking framework, go under the assumption that map's signature is public <U> RDD<U> map(scala.Function1<T, U>, scala.reflect.ClassTag<U>);
Hope that would work.

Scala type system, constrain member's type by parameter of own type

Not really sure the standard terminology here, so I'll try to describe what I'm trying to do. In case you're curious, the app I'm actually trying to write is an asynchronous task queue similar to Resque or rq.
I have a type TaskDef[ArgsT <: AnyVal, ResultT <: AnyVal]. In case you're curious, TaskDef represents "how to execute an asynchronous task which takes argument type ArgsT and result type ResultT, or, the code behind a task".
I'm trying to define a type TaskInst[DefT <: TaskDef]. In case you're curious, TaskInst represents "a TaskDef and associated argument to run it with, or, an actual task instance being submitted to the queue". TaskInst has two members, definition: DefT and arguments whose type I cannot write in code.
In English, my desired constraint is: "For a given DefT, where DefT is some TaskDef[ArgsT, ResultT], TaskInst[DefT] should contain a DefT and an ArgsT". That is, the argument type of the task definition should match the type of the argument given to the task.
How do I express this in the Scala type system?
Alternatively, am I modeling my domain incorrectly and attempting to do something un-idiomatic? Would some alternative approach be more idiomatic?
Thanks in advance!
EDIT:
I think my historical self writing Java would probably have resorted to unchecked casts at this point. This is definitely feasible with some amount of unchecked casts and just leaving out the constraint between the type of the TaskInst's arguments vs the type of the embedded TaskDef's arguments. But, I do wonder whether this is something the compiler can enforce, and hopefully without too scary a syntax.
Define them as abstract types:
trait TaskDef {
type Arguments <: AnyVal
type Result <: AnyVal
}
Then use a type projection:
trait TaskInst[DefT <: TaskDef] {
def definition: DefT
def arguments: DefT#Arguments
}
Live Demo
An add-on to the answer that #rightfold gave:
If you are looking to use type parameters throughout, you will need to properly pass the type parameters through to the type constructors.
Excuse me, that's a bit ambiguous for me to say it that way, so let me use my current code as a concrete example.
trait TaskDef[ArgT_, ResT_] {
type ArgT = ArgT_
type ResT = ResT_
val name: String
def exec(arg: ArgT): String \/ ResT
}
class TaskInst[ArgT, ResT, DefT <: TaskDef[ArgT, ResT]] (
val id: UUID,
val defn: DefT,
val arg: ArgT
)
The main divergence of my current code from #rightfold's example is that TaskDef takes type parameters. Then, when TaskInst's declaration references TaskDef, it must provide appropriate types to the type constructor.
I initially made the mistake of passing in placeholders. That is, I was writing class TaskInst[DefT <: TaskDef[_, _]. Turns out, this doesn't mean what I thought it meant. (I don't know. Perhaps others might be inclined to follow the same line of thought. So, this is just a warning not to.) Don't do that, because then scalac will interpret the expected to mean a generated placeholder (which, as you might imagine, nothing matches), and then you get an obscure error message like the following.
[error] /Users/mingp/Code/scala-redis-queue/src/main/scala/io/mingp/srq/core/TaskInst.scala:8: type mismatch;
[error] found : TaskInst.this.arg.type (with underlying type _$1)
[error] required: _$1
[error] val arg: DefT#ArgT_
[error] ^
[error] one error found
Just posting this in hopes that future readers don't fall into the same hole I did.
EDIT:
As a further addendum, now that I've tried it out for a day, my impression is that this isn't actually a good data model for asynchronous tasks. You're better off combining, since stand-alone instances of TaskDef aren't really useful.