一聚教程网:一个值得你收藏的教程网站

最新下载

热门教程

如何正确使用 Mockito 进行依赖注入式单元测试:避免真实方法调用

时间:2026-07-09 10:03:58 编辑:袖梨 来源:一聚教程网

本文详解为何 Mockito 未生效的根本原因:被测类 ServiceClass 在方法内自行 new 实例,导致 @Mock 注入失效;并提供基于构造器注入的完整解决方案,确保 mock 行为真正生效。

本文详解为何 mockito 未生效的根本原因:被测类 `serviceclass` 在方法内自行 `new` 实例,导致 `@mock` 注入失效;并提供基于构造器注入的完整解决方案,确保 mock 行为真正生效。

在使用 Mockito 进行单元测试时,一个常见却极易被忽视的错误是:被测类内部直接 new 出依赖对象,而非通过依赖注入获取。这会导致即使你正确声明了 @Mock 和 @InjectMocks,Mockito 也无法接管该依赖——因为运行时实际调用的是全新创建的真实对象,而非你准备的 mock 实例。

回顾你的代码片段:

// ❌ 错误:ServiceClass 内部手动 new,绕过所有依赖注入public void sendPayload(final ValidRequest req) {    EncSercice encService = new EncSercice(); // ← 真实实例!mock 被完全忽略    String str = encService.callFn(req, keys);}

此时,@Mock EncSercice encService 和 @InjectMocks ServiceClass service 完全无效——service 对象虽被创建,但其内部逻辑始终使用新 new 的 EncSercice,因此你看到 callFn 的日志输出,且 Mockito.verify() 永远失败。

✅ 正确做法是:将依赖作为构造参数传入,使 ServiceClass 成为可测试的、依赖明确的组件

// ✅ 正确:ServiceClass 通过构造器接收依赖(推荐)public class ServiceClass {    private final EncSercice encService;    public ServiceClass(EncSercice encService) {        this.encService = Objects.requireNonNull(encService, "encService must not be null");    }    public void sendPayload(final ValidRequest req) {        // ... 其他逻辑        String str = encService.callFn(req, keys); // ← 调用的是注入的 mock 实例    }}

对应地,测试类需同步更新(使用现代 JUnit 5 + Mockito 4+ 推荐写法):

import org.junit.jupiter.api.BeforeEach;import org.junit.jupiter.api.Test;import org.mockito.Mock;import org.mockito.MockitoAnnotations;import static org.mockito.Mockito.*;class ServiceClassTest {    @Mock    private EncSercice encService;    private ServiceClass service;    @BeforeEach    void setUp() {        MockitoAnnotations.openMocks(this); // 替代已废弃的 initMocks()        service = new ServiceClass(encService); // 显式构造,确保 mock 被注入    }    @Test    void testEncryptRegisterTransactionPayload() {        // Given        ValidRequest request = new ValidRequest();        String stubbedResult = "Stubbed encrypted message";        when(encService.callFn(anyString(), any(String[].class)))                .thenReturn(stubbedResult);        // When        service.sendPayload(request);        // Then        verify(encService).callFn(anyString(), any(String[].class));        // 可选:验证行为是否符合预期(如无异常、返回值等)    }}

⚠️ 关键注意事项:

  • 禁止在被测类中 new 依赖对象:这是破坏可测试性的根本原因;
  • 优先使用构造器注入:比字段注入更清晰、更易测试、更符合不可变性原则;
  • @InjectMocks 仅对字段注入有效,且依赖于反射匹配,不推荐用于复杂场景;显式构造(如 new ServiceClass(mock))更可靠、更易调试;
  • 确保 EncSercice 类非 final(否则 Mockito 默认无法 mock),若必须为 final,需启用 mockito-inline 并配置 mock-maker-inline;
  • 使用 anyString() 和 any(String[].class) 匹配参数时,注意类型一致性(String[].class 是正确的 Class 字面量)。

总结:Mockito 的“stubbing 失效”问题,90% 源于被测类未遵循依赖注入原则。重构 ServiceClass 为构造器注入后,mock 行为将严格生效,测试可控、可验证、可维护。

热门栏目