You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求助:Mockito无法Mock Final类方法的替代解决方案

问题描述

我需要对服务中这段代码的execute()、context()和build()方法做Mock:

Attributes attributes = targetClient.getAttributes(
                    TargetDeliveryRequest.builder()
                            .execute(new ExecuteRequest().mboxes(Collections.singletonList(mboxRequest)))
                            .context(new Context().channel(ChannelType.WEB)).build());

TargetDeliveryRequest是第三方库类,无法修改,核心定义如下:

public class TargetDeliveryRequest {
    ....
    public static TargetDeliveryRequestBuilder builder() {
        return new TargetDeliveryRequestBuilder();
    }

}

我尝试MockTargetDeliveryRequestBuilder:

TargetDeliveryRequestBuilder targetDeliveryRequestBuilder = mock(TargetDeliveryRequestBuilder.class);

但该类是final类,测试时抛出错误:

org.mockito.exceptions.base.MockitoException:
Cannot mock/spy class com.adobe.target.edge.client.model.TargetDeliveryRequestBuilder
Mockito cannot mock/spy because : - final class

TargetDeliveryRequestBuilder的关键代码:

public final class TargetDeliveryRequestBuilder {
    ...
    TargetDeliveryRequestBuilder() {
    }
    ...
    public TargetDeliveryRequestBuilder context(Context context) {
        this.request.context(context);
        return this;
    }

    public TargetDeliveryRequestBuilder execute(ExecuteRequest execute) {
        this.request.execute(execute);
        return this;
    }
    ...
    public TargetDeliveryRequest build() {
        this.setTargetValues();
        this.setVisitorValues();
        this.createVisitorId();
        this.setExperienceCloudValues();
        TargetDeliveryRequest targetDeliveryRequest = TargetDeliveryRequest.fromRequest(this.request);
        targetDeliveryRequest.setLocationHint(this.locationHint);
        targetDeliveryRequest.setSessionId(this.sessionId);
        targetDeliveryRequest.setVisitor(this.visitor);
        targetDeliveryRequest.setDecisioningMethod(this.decisioningMethod);
        return targetDeliveryRequest;
    }
    ...
}

已知添加mockito-inline可解决问题,但项目版本较旧,引入后会破坏大量现有测试,因此该方案不可行。

环境版本:

  • Java: 8
  • mockito-core: 3.12.4
  • powermock-module-junit: 2.0.9
  • powermock-api-mockito2: 2.0.9
可行解决方案

利用项目已引入的PowerMock依赖,可通过以下步骤实现Mock:

  1. 配置测试类注解
    在测试类上添加PowerMock的Runner注解,并指定需要处理的类:
@RunWith(PowerMockRunner.class)
@PrepareForTest({TargetDeliveryRequest.class, TargetDeliveryRequestBuilder.class})
public class YourServiceTest {
    // 测试逻辑
}
  1. Mock静态builder方法
    用PowerMock拦截TargetDeliveryRequest.builder()的静态调用,返回Mock的builder实例:
// 静态Mock TargetDeliveryRequest类
mockStatic(TargetDeliveryRequest.class);
TargetDeliveryRequestBuilder mockBuilder = mock(TargetDeliveryRequestBuilder.class);
// 指定builder()返回Mock实例
when(TargetDeliveryRequest.builder()).thenReturn(mockBuilder);
  1. Mock链式调用方法
    由于builder采用链式调用(方法返回自身),需要依次Mockexecute()、context()返回自身,再Mockbuild()返回目标对象:
// Mock execute方法,返回builder自身
when(mockBuilder.execute(any(ExecuteRequest.class))).thenReturn(mockBuilder);
// Mock context方法,返回builder自身
when(mockBuilder.context(any(Context.class))).thenReturn(mockBuilder);
// Mock build方法,返回自定义的TargetDeliveryRequest实例(也可以Mock这个实例)
TargetDeliveryRequest mockDeliveryRequest = mock(TargetDeliveryRequest.class);
when(mockBuilder.build()).thenReturn(mockDeliveryRequest);
  1. Mock getAttributes方法
    最后MocktargetClient.getAttributes()的返回值,得到你需要的Attributes实例:
TargetClient mockTargetClient = mock(TargetClient.class);
Attributes mockAttributes = mock(Attributes.class);
when(mockTargetClient.getAttributes(mockDeliveryRequest)).thenReturn(mockAttributes);

通过这套配置,就能完整Mock这段链式调用逻辑,无需引入mockito-inline,不会影响现有测试。


内容的提问来源于stack exchange,提问作者Gustavo Rey

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 08:40:33