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
相关产品推荐
相关产品推荐

