从测试类CUT
中提取:
def compileOutputLines( TopDocs topDocs ) {
println "gubbins"
}
测试代码:
def "my feature"(){
given:
CUT stubCut = Stub( CUT ){
compileOutputLines(_) >> { TopDocs mockTD ->
// NB no Exception is thrown
// try {
println "babbles"
callRealMethod()
println "bubbles"
// }catch( Exception e ) {
// println "exception $e"
// }
}
}
CUT spyCut = Spy( CUT ){
compileOutputLines(_) >> { TopDocs mockTD ->
println "babbles 2"
callRealMethod()
println "bubbles 2"
}
}
when:
stubCut.compileOutputLines( Mock( TopDocs ))
spyCut.compileOutputLines( Mock( TopDocs ))
then:
true
}
输出到stdout
:
喋喋不休
泡泡
bab呀2 格宾斯
泡泡2
我试图在线找到完整的Spock Framework Javadoc链接......但我找不到它......“非框架”Javadoc是MaterialIcons,但你找不到索引中的方法callRealMethod
。
从我从源本地生成的Javadoc API,我确实可以找到这个方法:它是org.spockframework.mock.IMockInvocation
的方法。它说:
java.lang.Object callRealMethod()
将此方法调用委托给底层的真实对象 模拟对象,包括任何方法参数。如果这个模拟对象有 没有底层真实对象,一个CannotInvokeRealMethodException 抛出。
返回: 委托此调用的方法的返回值
我的理解(例如它)是Stub应该导致这个Exception
被抛出。但似乎并非如此。来自专家的任何评论?
答案 0 :(得分:3)
这是一个有趣的问题。从理论上讲,我的答案是:
callRealMethod()
仅适用于间谍,不适用于模拟或存根。它也只在关于间谍的章节中提到过,你注意到了吗?想一想:间谍包裹了一个真实的物体,所以你可以参考一个你可以调用的真实方法。对于只是无操作子类的模拟和存根,情况也是如此。如果你可以为一个存根调用一个真正的方法,它将是一个间谍。
实际上,我在Spock 1.1(Groovy 2.4)的测试中看到了与你的不同甚至更奇怪的行为:无论我使用模拟,存根还是间谍,callRealMethod()
总是< / strong>调用真正的方法。这真是一个惊喜。所以,是的,这种行为与我的预期不同。在调试时查看接口实现的源代码,我也看不到对mock对象类型的任何检查(它是间谍还是没有?)。真正的方法只是被识别和调用。
查看类DynamicProxyMockInterceptorAdapter
我找到了这种行为的解释:IMockInvocation
Javadoc中提到的异常仅在尝试为接口类型mock调用实际方法时抛出,从不用于模拟或类类型对象:
public Object invoke(Object target, Method method, Object[] arguments) throws Throwable {
IResponseGenerator realMethodInvoker = (ReflectionUtil.isDefault(method) || ReflectionUtil.isObjectMethod(method))
? new DefaultMethodInvoker(target, method, arguments)
: new FailingRealMethodInvoker("Cannot invoke real method '" + method.getName() + "' on interface based mock object");
return interceptor.intercept(target, method, arguments, realMethodInvoker);
}
所以句子“如果这个模拟对象没有潜在的真实对象,则抛出异常(...)异常”本质上是正确的,但是含糊不清,因为它没有解释什么是“潜在的真实”对象“的意思。你的假设是错的,我的也是。为我们双方学到的经验教训。
现在什么时候能看到描述的行为?
package de.scrum_master.stackoverflow;
public interface MyInterface {
void doSomething();
}
package de.scrum_master.stackoverflow
import org.spockframework.mock.CannotInvokeRealMethodException
import spock.lang.Specification
class MyInterfaceTest extends Specification {
def "Try to call real method on interface mock"() {
given:
MyInterface myInterface = Mock() {
doSomething() >> { callRealMethod() }
}
when:
myInterface.doSomething()
then:
thrown(CannotInvokeRealMethodException)
}
def "Try to call real method on interface stub"() {
given:
MyInterface myInterface = Stub() {
doSomething() >> { callRealMethod() }
}
when:
myInterface.doSomething()
then:
thrown(CannotInvokeRealMethodException)
}
def "Try to call real method on interface spy"() {
given:
MyInterface myInterface = Spy() {
doSomething() >> { callRealMethod() }
}
when:
myInterface.doSomething()
then:
thrown(CannotInvokeRealMethodException)
}
}
更新:我刚刚创建了issue #830,要求改进Spock的文档。