使用Spock替代JUnit编写单元测试时Mock Provider<T>.get()遭遇MissingMethodInvocationException的原因排查
你遇到的核心问题是混用了Spock原生Mock和Mockito的API——这两个框架的Mock机制完全独立,不能混搭使用,咱们一步步拆解原因和解决方案:
为什么第一种方式会抛出异常
你用Provider<SomeOjb> a = Mock()创建的是Spock原生生成的Mock对象,而非Mockito的Mock实例。Mockito的when()方法只能识别自己框架生成的Mock,当你把Spock Mock传给它时,它根本认不出这是一个Mockito Mock,自然就会抛出MissingMethodInvocationException,提示你传入的不是Mockito Mock上的方法调用。
第二种方式的语法错误原因
Groovy对泛型尖括号<>的语法解析和Java略有不同:直接写def a = Mock(Provider<SomeObj>)时,Groovy会错误地把<>当成比较运算符,导致语法报错。正确的写法有两种:
- 显式指定变量类型:
Provider<SomeObj> a = Mock() - 用类型转换:
def a = Mock(Provider) as Provider<SomeObj>
第三种方式正常工作的原因
你用@Mock Provider<SomeObj> a;注解创建的是Mockito的Mock对象(前提是你给测试类加了Mockito的扩展,比如@ExtendWith(MockitoExtension.class)或者Spock的Mockito集成配置),这时候配合Mockito的when().thenReturn()完全是配套用法,所以能正常运行。
正确的两种实现方式
方式一:纯Spock原生Mock(推荐)
Spock自带的Mock语法比Mockito更简洁,完全不需要依赖Mockito的API:
Provider<SomeObj> a = Mock() def setup() { SomeObj obj = new SomeObj() // Spock用>>来指定方法返回值,等价于Mockito的when().thenReturn() a.get() >> obj }
方式二:纯Mockito Mock(适合习惯Mockito语法的场景)
如果你更熟悉Mockito的写法,确保全程用Mockito的Mock创建方式:
@Mock Provider<SomeObj> a def setup() { SomeObj obj = new SomeObj() Mockito.when(a.get()).thenReturn(obj) }
记得给测试类添加Mockito扩展注解:@ExtendWith(MockitoExtension.class),或者在Spock的配置中启用Mockito集成。
内容的提问来源于stack exchange,提问作者Suule

