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

Mockito模拟方法却触发真实方法执行的问题求助

问题排查与解决方案

核心原因

你的模拟对象没生效,是因为CisRestBaseService的构造函数里直接硬实例化了CisApiConfig,和你测试代码中创建的模拟externalApiConfig完全是两个独立对象。当CisAccountServiceImpl(推测它继承自CisRestBaseService)初始化时,会调用父类构造函数创建真实的CisApiConfig实例,自然会执行真实的getExternalUrl()方法去读文件。

修复步骤

要让Mock对象生效,必须把ExternalApiConfig的创建权从类内部转移出来,通过构造函数注入的方式传入,这样测试时就能替换成模拟对象。

1. 重构CisRestBaseService,支持构造函数注入

修改父类代码,新增带参数的构造函数,接受外部传入的ExternalApiConfig:

public class CisRestBaseService {

    protected WebTarget rootWebTarget;
    protected ExternalApiConfig externalApiConfig;

    // 新增:通过构造函数注入配置对象
    public CisRestBaseService(ExternalApiConfig externalApiConfig) {
        JacksonJsonProvider jacksonJsonProvider = new JacksonJaxbJsonProvider()
                .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
                .configure(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE, false);

        Client jaxRsClient = ClientBuilder.newClient().register(jacksonJsonProvider);
        this.externalApiConfig = externalApiConfig; // 使用外部传入的对象
        this.rootWebTarget = jaxRsClient.target(externalApiConfig.getExternalUrl());
    }

    // 保留原有无参构造(兼容旧代码),内部调用带参构造创建真实对象
    public CisRestBaseService() {
        this(new CisApiConfig());
    }
}

2. 调整子类CisAccountServiceImpl,传递注入的配置

如果CisAccountServiceImpl是CisRestBaseService的子类,需要添加对应的构造函数,把注入的配置传递给父类:

public class CisAccountServiceImpl extends CisRestBaseService {
    // 新增构造函数,接收配置并传给父类
    public CisAccountServiceImpl(ExternalApiConfig externalApiConfig) {
        super(externalApiConfig);
    }

    // 你的业务方法...
}

3. 修改测试代码,传入模拟对象

移除冗余的mock操作,在创建CisAccountServiceImpl实例时传入模拟的externalApiConfig:

@Mock
private ExternalApiConfig externalApiConfig;
public CisAccountServiceImpl cisAccoutService;

@BeforeMethod
public void init() {
    MockitoAnnotations.initMocks(this);
    // 删掉冗余的mock创建:externalApiConfig = Mockito.mock(CisApiConfig.class);
    // @Mock注解已经帮你创建了模拟对象
}

private void testUpdateServiceAddressCoordinates(Account account) throws IOException {
    // 指定模拟方法的返回值
    Mockito.when(externalApiConfig.getExternalUrl()).thenReturn("http://localhost:8080/serviceURI/");
    // 创建服务实例时传入模拟的配置对象
    cisAccoutService = new CisAccountServiceImpl(externalApiConfig);
    
    // 后续测试逻辑保持不变
    assertThat(account, is(notNullValue()));
    List<PremiseExtension> premiseExtensions = account.getPremise().getPremiseExtension();
    assertThat(premiseExtensions.size(), is(30));
    String geoXSettingName = "value2";
    String geoYSettingName = "value3";
    Double lat = 24.0;
    Double lng = -98.0;
    boolean updated = cisAccoutService.updateAccountGeoLocation(accountId,
            lat, lng, geoXSettingName, geoYSettingName);
    assertThat(true, is(updated));
    Account updatedAccount = getAccountById();
    assertThat(Double.parseDouble(updatedAccount.getPremise().getPremiseExtension().get(2).getValue()), is(lat));
    assertThat(Double.parseDouble(updatedAccount.getPremise().getPremiseExtension().get(3).getValue()), is(lng));
    // 回滚修改
    updatedAccount.getPremise().setPremiseExtension(premiseExtensions);
    updateAccountWithValues(updatedAccount);
}

这样修改后,测试时CisRestBaseService会使用你模拟的externalApiConfig对象,调用getExternalUrl()时就会返回你指定的字符串,而不是执行真实方法去读文件。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 19:02:39