Mocking of non-interface types requires the CGLIB library.

在SpringCloud微服务架构中使用Spock框架进行单元测试时,遇到无法Mock非接口类型的错误。通过添加CGlib依赖,成功解决了问题,使单元测试得以顺利执行。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

spring cloud微服务架构中引入spock单元测试框架,且采用given-when-then-where子句,包含Mock对象时,执行单元测试案例失败,提示如下错误:

org.spockframework.mock.CannotCreateMockException: Cannot create mock for class com.xxx.xxx.xxx.xxx. Mocking of non-interface types requires the CGLIB library. Please put cglib-nodep-2.2 or higher on the class path.
	at org.spockframework.mock.runtime.ProxyBasedMockFactory.create(ProxyBasedMockFactory.java:52)
	at org.spockframework.mock.runtime.JavaMockFactory.create(JavaMockFactory.java:51)
	at org.spockframework.mock.runtime.CompositeMockFactory.create(CompositeMockFactory.java:44)
	at org.spockframework.lang.SpecInternals.createMock(SpecInternals.java:45)
	at org.spockframework.lang.SpecInternals.createMockImpl(SpecInternals.java:281)
	at org.spockframework.lang.SpecInternals.MockImpl(SpecInternals.java:99)
	at com.dashuf.fs.api.FileStoreAPITest.$spock_initializeFields(FileStoreAPITest.groovy:11)

单测代码如下:

    @Unroll
    def "case 01 getSignedString no exception"() {
        given: "获取结果数据"
            def signature = new String("signature")
        when: "获取签名串"
            fileStoreService.getSignedString(_) >> signature
        then:
            def ressign = fileStoreAPI.getSignedString(fileId as String)
            ressign.equals(result)
        where:
            fileId | result
            "01" | "signature"
            "02" | "signature"
            "03" | "signature"
            "04" | "signature"
            "05" | "signature"
    }

根据提示,推测应该是少了cglib库,后面查阅资料得知:在默认情况下,Spock 只能 Mock 接口,增加 cglib 依赖之后,能够 Mock 类。
于是我们在build.gradle中引入依赖如下(版本请可自行调整):

compile(group: 'cglib', name: 'cglib-nodep', version: '3.1')

如果是采用maven则在pom.xml中加入如下依赖:

        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib-nodep</artifactId>
            <version>3.1</version>
        </dependency>

重新构建工程,单元测试执行成功

<think>嗯,用户问了两个关于Mockito框架的问题。首先,我需要理解每个问题的核心内容,然后逐步解答。 第一个问题是关于无法stub或verify某些方法,比如final、private、equals()、hashCode()。这些方法为什么不能被打桩或验证呢?记得Mockito在生成mock对象时,通常是通过继承目标类并覆盖其中的方法来实现的。对于final方法,子类无法覆盖,所以Mockito无法处理。private方法同理,因为子类无法访问父类的私有方法,自然也无法覆盖。而equals()和hashCode()通常是Object类中的方法,Mockito可能默认不处理这些方法,或者由于内部实现的原因,不允许用户自己stub,否则可能破坏Mockito的内部机制。 第二个问题提到在when()中调用了其他对象的方法,而不是mock对象的方法。这时候会导致Mockito无法正确记录调用。比如,如果when里调用了真实对象的方法,或者另一个mock对象的方法没有正确设置,Mockito的when会无法捕获到正确的调用,从而导致后续验证失败或者stub不生效。需要检查是否在mock对象上调用方法,并且确保在调用方法前已经配置好了相应的stub。 接下来要组织语言,用中文清晰解释这两个问题。分点回答,每个问题给出原因和解决方案,可能的话加上示例代码。注意用户提到的系统级指令,数学公式要用$...$,但这里可能不太涉及。结构上需要步骤化,帮助用户逐步理解问题所在以及如何解决。 对于第一个问题,可以分点列出不能stub的方法类型,并分别解释原因,然后给出解决方法,比如使用PowerMockito或者封装私有方法。对于第二个问题,强调在when()中必须调用mock对象的方法,并给出正确和错误的示例对比,让用户明白哪里出错了。 需要检查是否有LaTeX格式的问题,但这里可能更多是代码块的展示。确保代码正确使用反引号包裹,并且语法正确。同时,保持回答真实可靠,避免猜测不确定的内容,比如Mockito的内部实现机制,可以适当提及可能的原理,但明确说明可能的情况。 总结下来,回答的结构应该是先分别处理两个问题,每个问题下分点说明原因和解决方案,使用代码示例辅助说明,并确保语言简洁易懂,符合中文表达习惯。</think>### 问题1:无法对 `final`/`private`/`equals()`/`hashCode()` 方法进行打桩(Stub)或验证 **原因与解决方案:** 1. **`final` 方法** - **原因**:Mockito 通过生成目标类的子类来创建 Mock 对象。由于 `final` 方法无法被子类覆盖,因此无法被 Mockito 打桩或验证。 - **解决方案**: - 使用 PowerMockito(需额外依赖)来增强 Mockito,支持对 `final` 方法的 Mock- 重构代码,尽量避免对 `final` 方法直接依赖。 2. **`private` 方法** - **原因**:私有方法对外部不可见,Mockito 无法通过常规方式代理这些方法。 - **解决方案**: - 不要直接对私有方法打桩,而是通过测试公有方法间接验证私有逻辑。 - 使用反射工具(如 `Whitebox`)调用私有方法(不推荐,可能破坏封装性)。 3. **`equals()`/`hashCode()` 方法** - **原因**:这些方法属于 `Object` 类,Mockito 的默认行为会直接调用真实方法。如果手动打桩,可能破坏 Mockito 内部逻辑(如验证调用次数)。 - **解决方案**: - 避免对 `equals()`/`hashCode()` 打桩,改用真实实现。 - 若必须 Mock,需通过自定义 `Answer` 或继承 `Object` 的包装类实现。 --- ### 问题2:在 `when()` 中调用非 Mock 对象的方法 **错误示例**: ```java // 假设 mockA 是 Mock 对象,realB 是真实对象 when(realB.someMethod()).thenReturn("value"); // 错误!realB 不是 Mock 对象 ``` **原因**: - `when()` 的作用是记录 Mock 对象上的方法调用。若在 `when()` 中调用非 Mock 对象的方法,Mockito 无法追踪该调用,导致后续打桩失效或抛出异常。 **正确做法**: 1. **确保调用的是 Mock 对象的方法**: ```java // 正确示例:对 Mock 对象打桩 when(mockA.someMethod()).thenReturn("value"); ``` 2. **若需对真实对象的部分方法打桩**: - 使用 `spy()` 包装真实对象,再对特定方法打桩: ```java List<String> realList = new ArrayList<>(); List<String> spyList = spy(realList); // 创建 Spy 对象 when(spyList.size()).thenReturn(100); // 对 size() 打桩,其他方法调用真实逻辑 ``` --- ### 总结 1. **限制性方法**:避免直接 Mock `final`/`private`/`equals()`/`hashCode()`,优先通过设计优化或工具扩展解决。 2. **对象作用域**:在 `when()` 中始终操作 Mock/Spy 对象,确保 Mockito 能正确拦截调用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值