有没有办法让GroovyMock在Spock中接受GString作为String参数?

问题描述

很遗憾,我找不到有关此主题的任何有用信息。

我有一些Spock测试,需要使用GroovyMock而不是Mock-因为它支持模拟动态方法

(非动态)方法之一采用String参数。有时,会将GString作为参数传递给该方法。在生产代码以及Mock中,这都可以正常工作。

但是,切换到GroovyMock之后,我遇到了java.lang.IllegalArgumentException: argument type mismatch异常,将我指向以下行(请参见下面的示例):

        someClass.someMethod("foo ${1 + 1}")

我已经检查了创建GroovyMock期间可用的某些选项是否有帮助。到目前为止,我尝试了verified选项-不幸的是,该选项没有帮助。其他选项似乎甚至没有机会在这里有用,因此我没有尝试使用它们(并且对于大多数它们,我什至都不知道如何使用它们)。

请检查以下小示例以供参考:

import spock.lang.Specification

class SomeClass {
    String someMethod(String arg) {
        return arg
    }
}

class TestClass {
    SomeClass someClass

    String callMethod() {
        someClass.someMethod("foo ${1 + 1}")
    }
}

class FooSpec extends Specification {
    def 'pass String to groovyMock mocked method taking a String argument'() {
        given:
        TestClass testClass = new TestClass()
        SomeClass someClass = GroovyMock() // does not work
        // SomeClass someClass = Mock() // test works if used instead of the prevIoUs line
        testClass.someClass = someClass

        when:
        testClass.callMethod()

        then:
        1 * someClass.someMethod(_)
    }
}

解决方法

好收获!我可以在Spock 1.3-groovy-2.52.0-M3-groovy-3.0中确认这种行为。我认为创建一个Spock issue并从那里链接回这个问题是很有意义的。

我已调试问题并在“清理”用于测试错误报告之前打印了堆栈跟踪。您可能需要将其添加到新版本中:

java.lang.IllegalArgumentException: argument type mismatch
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:104)
    at org.spockframework.mock.runtime.GroovyMockMetaClass.doInvokeMethod(GroovyMockMetaClass.java:83)
    at org.spockframework.mock.runtime.GroovyMockMetaClass.invokeMethod(GroovyMockMetaClass.java:39)
    at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.call(PogoMetaClassSite.java:41)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:115)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:127)
    at de.scrum_master.stackoverflow.q63797837.TestClass.callMethod(FooSpec.groovy:15)
    at de.scrum_master.stackoverflow.q63797837.TestClass$callMethod.call(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:115)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:119)
    at de.scrum_master.stackoverflow.q63797837.FooSpec.$spock_feature_0_0(FooSpec.groovy:28)
    ... 34 more

更新:另一个发现:如果将目标方法签名更改为String someMethod(GString arg),则测试将与GroovyMock一起通过。因此,问题可能与以某种方式将GString中使用的someClass.someMethod("foo ${1 + 1}")转换为String有关。


更新2020-09-16::几天前,我代表您创建了Spock issue #1216,因为您自己忽略了我的建议。该错误已得到修复,我希望它可以在下一个2.0里程碑版本中发布,当然也可以在最终版本中发布。