Call-by-name parameters are actually compiled into something like this:
trait Client {
def compute(valueFunction => Function0[String]): String
}
and the call is converted into something like this
client.compute(() => { getValue() })
or putting it more explicitly:
client.compute(new Funciton0[String]{ def apply():String = { getValue() }})
So Mockito returns doesn't work because in two calls of the compute the parameter being passed is actually two different Function0 objects. And because equals is not overridden for Function0, they don't match.
The trick to work this around is to first explicitly convert your getValue method into a local Function0[String] variable. This seems to be enough to make two client.compute calls generate identical objects for Mockito to work. So you may try to use following code:
import org.specs2._
import org.specs2.mock.Mockito
class Specs2Test extends Specification with Mockito {
override def is =
s2"""
this works $good
this doesn't $bad
"""
final def getValue: String = {
"value"
}
def good = {
val client: Client = mock[Client]
val f: Function0[String] = getValue _
client.compute(f()) returns "result"
client.compute(f()) mustEqual "result"
}
def bad = {
val client: Client = mock[Client]
client.compute(getValue) returns "result"
client.compute(getValue) mustEqual "result" // fails. returns null
}
}
Update
If what you actually test is not client.compute but some other method in Java that inside calls client.compute and you want to mock that call, I don't know how to help you preserving exact semantics without rewriting at least some of your code. Probably the simplest thing I can think of is to use Funciton0 in the signature explicitly and then use Matchers.any such as
trait Client {
def compute(value: () => String): String
}
and then
def usingMatchAny = {
val client: Client = mock[Client]
client.compute(ArgumentMatchers.any()) returns "result"
// actually here you call the method that uses client.compute call
client.compute(getValue _) mustEqual "result"
}