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

Mockito:如何模拟并断言抛出异常,解决不必要存根错误

问题分析

你遇到的unnecessary Mockito stubbings错误,本质是你给某个方法做了存根(stub),但整个测试过程中这个存根的方法根本没被调用。看你的测试代码,你存根了securityManagerService.restoreRight("a")会抛出异常,但测试方法里既没直接调用它,也没通过调用requireRight间接触发它,Mockito的默认严格校验就会报错。

另外,你的代码还有个冗余问题:@Mock注解和手动mock(SecurityManagerService.class)重复了——用了@RunWith(MockitoJUnitRunner.class)之后,@Mock会自动帮你创建Mock实例,不需要手动调用mock方法,这部分可以删掉。

正确实现步骤

要测试requireRight方法在restoreRight抛出异常时的行为,你需要:

  1. 移除冗余的Mock初始化代码
  2. 确保测试中实际调用requireRight方法(触发内部的restoreRight调用,用到你存根的逻辑)
  3. 用合适的方式断言异常的抛出

修正后的代码(JUnit 4)

@RunWith(MockitoJUnitRunner.class)
public class SecurityManagerServiceTest {
    // 去掉手动mock,@Mock会自动初始化实例
    @Mock
    private SecurityManagerService securityManagerService;

    @Test(expected = SecurityException.class) // JUnit4 基础异常断言方式
    public void testRequireAll_WhenRestoreRightThrows_ShouldThrowSecurityException() {
        // 1. 存根loggerUser方法,返回模拟用户
        when(securityManagerService.loggerUser()).thenReturn(fakeUser());
        // 2. 指定调用requireRight时执行真实方法(测试真实业务逻辑)
        doCallRealMethod().when(securityManagerService).requireRight(anyString());
        // 3. 存根restoreRight("a")抛出异常
        when(securityManagerService.restoreRight("a")).thenThrow(SecurityException.class);

        // 4. 关键:调用requireRight,触发内部的restoreRight调用
        securityManagerService.requireRight("a");
    }

    // 假设你的模拟用户生成方法是这样的
    private User fakeUser() {
        User user = new User();
        // 按需设置用户属性
        return user;
    }
}

更灵活的异常断言(推荐)

如果用JUnit 4的expected注解,只能断言抛出指定异常,无法对异常做更多验证(比如异常消息)。你可以用try-catch结合断言,或者配合Mockito的验证方法:

@Test
public void testRequireAll_WhenRestoreRightThrows_ShouldThrowSecurityException() {
    // 前置存根逻辑不变
    when(securityManagerService.loggerUser()).thenReturn(fakeUser());
    doCallRealMethod().when(securityManagerService).requireRight(anyString());
    when(securityManagerService.restoreRight("a")).thenThrow(new SecurityException("权限验证失败"));

    // 捕获并验证异常细节
    try {
        securityManagerService.requireRight("a");
        // 如果没抛出异常,直接标记测试失败
        fail("Expected SecurityException to be thrown");
    } catch (SecurityException e) {
        assertEquals("权限验证失败", e.getMessage());
        // 可选:验证restoreRight确实被调用了一次
        verify(securityManagerService).restoreRight("a");
    }
}

关于Mockito严格模式

如果你确实有存根但暂时不想被校验(不推荐长期使用),可以在测试类上添加@MockitoSettings(strictness = Strictness.LENIENT)关闭严格模式,但最好的方式还是确保所有存根都被用到,或者直接移除不必要的存根。

内容的提问来源于stack exchange,提问作者Nunyet Calçada

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 08:49:06