
mockito 默认不会自动替换被测类内部新建的对象,若目标方法在类构造或运行时自行实例化依赖(如 new cisapiconfig()),即使已 mock 该类型,也不会生效;必须通过依赖注入将 mock 对象显式传入被测类。
mockito 默认不会自动替换被测类内部新建的对象,若目标方法在类构造或运行时自行实例化依赖(如 new cisapiconfig()),即使已 mock 该类型,也不会生效;必须通过依赖注入将 mock 对象显式传入被测类。
在使用 Mockito 进行单元测试时,一个常见误区是:仅对某个接口或类创建了 Mock 对象,却未将其实际注入到被测对象中。正如本例所示,CisRestBaseService 在无参构造函数中直接执行 new CisApiConfig() 并调用其 getExternalUrl() 方法——此时 Mockito 完全无法干预该实例的行为,因此文件读取逻辑仍会真实触发,导致测试失败或环境依赖。
✅ 正确做法是采用构造器注入(Constructor Injection),使被测类的依赖可被外部控制:
public class CisRestBaseService {
protected WebTarget rootWebTarget;
protected ExternalApiConfig externalApiConfig;
// 新增带参构造器:支持注入 mock 实例
public CisRestBaseService(ExternalApiConfig config) {
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 = config; // ← 关键:使用传入的 mock 实例
this.rootWebTarget = jaxRsClient.target(externalApiConfig.getExternalUrl());
}
// 保留原有无参构造器(供生产环境使用),委托给带参构造器
public CisRestBaseService() {
this(new CisApiConfig()); // ← 生产环境仍使用真实配置
}
}
相应地,测试代码需配合调整,确保 CisAccountServiceImpl(假设它继承或组合了 CisRestBaseService)能接收并使用该 mock 配置:
@Mock
private ExternalApiConfig externalApiConfig;
@BeforeMethod
public void init() {
MockitoAnnotations.openMocks(this); // 推荐使用 openMocks 替代已弃用的 initMocks
}
@Test
public void testUpdateServiceAddressCoordinates() throws IOException {
// 1. 配置 mock 行为
Mockito.when(externalApiConfig.getExternalUrl())
.thenReturn("http://localhost:8080/serviceURI/");
// 2. 构造被测服务时传入 mock 配置(关键!)
cisAccoutService = new CisAccountServiceImpl(externalApiConfig);
// 3. 执行业务逻辑断言(略去具体 account 初始化细节)
boolean updated = cisAccoutService.updateAccountGeoLocation(
accountId, 24.0, -98.0, "value2", "value3");
assertThat(updated).isTrue();
// 后续验证逻辑...
}
⚠️ 注意事项:
- 不要在被测类中 new 实例:任何硬编码的 new XxxConfig() 都会绕过 Mock,破坏测试隔离性;
- 优先使用构造器注入而非字段注入:更易测试、语义清晰、符合不可变设计原则;
- 验证 mock 是否被调用(可选增强):Mockito.verify(externalApiConfig).getExternalUrl(); 可确认方法确实被触发且走的是 mock 分支;
- 若无法修改被测类源码(如第三方库),可考虑 @Spy + doReturn(...).when(...) 组合,或使用 PowerMock(不推荐,增加复杂度)。
总结:Mockito 的“模拟”本质是对象替换,而非“方法拦截”。只有当被测代码真正持有了你创建的 Mock 实例时,.when(...).thenReturn(...) 才会生效。依赖注入不仅是设计最佳实践,更是可测试性的基石。










