3.1 严格Stubbing模式

严格Stubbing(Strict Stubbing)是Mockito提供的一种增强测试严谨性的模式,旨在检测以下问题:

  • 多余的Stubbing:配置了未被调用的方法桩。
  • 不必要的Stubbing:Stubbing未被使用且不影响测试结果。
  • 桩顺序错误:Stubbing被覆盖或错误使用。

通过严格模式,可以避免测试代码中的“虚假通过”(False Positive),确保每个Stubbing都有明确的目的。


1. 启用严格Stubbing

Mockito提供了两种方式启用严格模式:

1.1 全局启用(推荐)

在测试类上添加 @MockitoSettings(strictness = Strictness.STRICT_STUBS)

@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.STRICT_STUBS) // 全局启用严格模式
public class OrderServiceTest {
    // 测试代码...
}
1.2 手动启用

通过 MockitoSession 在单个测试中启用:

@Test
void testWithManualStrictness() {
    try (MockitoSession session = Mockito.mockitoSession()
            .strictness(Strictness.STRICT_STUBS)
            .startMocking()) {
        // 测试代码...
    }
}

2. 严格模式下的错误场景与示例
2.1 多余的Stubbing

问题:配置了未被调用的Stubbing。
示例

@Mock
private UserDao mockUserDao;

@Test
void findUser_ShouldReturnUser() {
    // 多余的Stubbing:findByEmail未被调用
    when(mockUserDao.findByUsername("alice")).thenReturn(new User());
    when(mockUserDao.findById(1)).thenReturn(new User()); // 实际被调用的Stubbing

    User user = userService.findUserById(1); // 调用findById(1)

    verify(mockUserDao).findById(1);
}

错误信息

Unnecessary stubbings detected.
2.2 不必要的Stubbing

问题:Stubbing存在但未被使用,且不影响测试结果。
示例

@Test
void createUser_ShouldNotDependOnFindMethod() {
    when(mockUserDao.findByUsername("alice")).thenReturn(null); // 未被使用
    doNothing().when(mockUserDao).save(any());

    userService.createUser("alice", "pass123");
    
    verify(mockUserDao).save(any());
}

错误信息:同上,提示存在不必要的Stubbing。


3. 解决方案
3.1 删除多余的Stubbing

直接移除未被调用的桩代码:

@Test
void findUser_ShouldReturnUser() {
    // 删除多余的findByUsername桩
    when(mockUserDao.findById(1)).thenReturn(new User());

    User user = userService.findUserById(1);
    verify(mockUserDao).findById(1);
}
3.2 显式标记宽松Stubbing

使用 lenient() 忽略特定Stubbing的检测:

@Test
void createUser_ShouldAllowUnusedStubbing() {
    // 标记为宽松Stubbing
    lenient().when(mockUserDao.findByUsername("alice")).thenReturn(null);
    doNothing().when(mockUserDao).save(any());

    userService.createUser("alice", "pass123");
    verify(mockUserDao).save(any());
}

4. 严格模式的进阶用法
4.1 验证Stubbing顺序

严格模式会检测Stubbing的覆盖顺序。例如,重复定义同一方法的Stubbing可能导致意外覆盖:

@Test
void testStubbingOrder() {
    when(mockList.get(0)).thenReturn("A");
    when(mockList.get(0)).thenReturn("B"); // 覆盖前一个Stubbing
    
    assertEquals("B", mockList.get(0)); // 通过
}

严格模式下会提示 PotentialStubbingProblem,建议使用 doReturn() 链式配置:

when(mockList.get(0))
    .thenReturn("A")
    .thenReturn("B");
4.2 检测无效的Stubbing参数

严格模式会检查参数匹配器的使用是否正确:

@Test
void testInvalidMatcher() {
    // 错误:混合精确值和匹配器
    when(mockUserDao.find(eq("alice"), anyString())).thenReturn(null);
}

错误信息

Invalid use of argument matchers!

5. 最佳实践
  • 仅Mock必要的交互:避免过度Mock,仅覆盖影响当前测试的依赖方法。
  • 及时清理无用桩代码:定期运行测试并修复严格模式提示的问题。
  • 合理使用 lenient():仅在明确需要时放宽检测,如共享测试配置中的通用桩。
  • 结合日志分析:通过 Mockito.mockingDetails(mock).printInvocations() 调试Stubbing调用。

总结

严格Stubbing模式通过强制检测冗余和无效的桩代码,显著提升单元测试的健壮性和可维护性。结合示例中的修复策略,开发者可以快速定位问题并优化测试逻辑,确保每个Stubbing都精准服务于测试目标。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值