当我试图运行以下测试代码时,我试图理解'Mockito'(specs2)中'间谍'功能的行为:
import org.specs2.mock.Mockito
import org.specs2.mutable.SpecificationWithJUnit
import org.specs2.specification.Scope
import scala.util.{Failure, Success, Try}
class Foo {
def foo(f: => Int): Unit = Try { f } match {
case Success(value) => value
case Failure(_) => foo1()
}
def foo1(): Unit = ???
}
class Boo {
def boo(): Int = ???
}
class SomeTestClass extends SpecificationWithJUnit {
"something" should {
"happen" in new Context {
mockedBoo.boo returns 1
spiedFoo.foo(mockedBoo.boo())
there was one(spiedFoo).foo1
}
}
}
trait Context extends Scope with Mockito {
val spiedFoo = spy(new Foo)
val mockedBoo = mock[Boo]
}
似乎在打电话时:
spiedFoo.foo(mockedBoo.boo())
在'Foo.foo'有机会运行它的代码之前评估模拟boo。我在'boo'中添加了一个断点并检查了栈跟踪,它告诉我它是由'MethodInterceptorFilter'调用的。更具体地说,'ArgumentsProcessor.argumentsToMatchers'看起来像这样:
if (!isCallRealMethod) {
// evaluate the byname parameter to collect the argument matchers
// if an exception is thrown we keep the value to compare it with the actual one (see "with Any" in the MockitoSpec and issue 82)
val value = try {
arg.asInstanceOf[Function0[_]].apply()
} catch {
case e: Throwable => e
}
// during the evaluation of the value some matchers might have been created. pull them.
val argumentsMatchers = ThreadSafeMockingProgress2.pullLocalizedMatchers
// if there are no matchers at all being registered this means that
// we are invoking the method, not verifying it
// in that case add a new matcher corresponding to the argument (an equals matcher using the value)
if (argumentsMatchers.isEmpty) matchers.add(new EqualsFunction0(value))
else {
// otherwise we add all the existing arguments matchers +
// we reset the state of the argumentMatchersStorage
matchers.addAll(argumentsMatchers.map(_.getActualMatcher))
ThreadSafeMockingProgress2.reportMatchers(argumentsMatchers.map(_.getActualMatcher))
}
}
它清楚地告诉我们:“评估byname参数以收集参数匹配器。”
如何避免评估by-name参数?
谢谢!