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

如何在调用pjp.proceed时抛出FooStudioException并模拟SpamException构造方法

问题场景

现有异常类

FooStudioException

public class FooStudioException extends SpamException {

    public FooStudioException(String message, String localizedMessage, Throwable cause) {
        super(SpamErrorCodes.INTERNAL_ERROR, message, localizedMessage, cause);
    }

    public FooStudioException(String message, String localizedMessage) {
        super(SpamErrorCodes.INTERNAL_ERROR, message, localizedMessage);
    }
}

SpamException

public class SpamException extends Exception {
    // 其他代码省略
    public SpamException(SpamErrorCodes codes, String message, String localizedMessage, Throwable cause) {
        super(message, cause);
        // 其他逻辑省略
    }
}

切面实现

FooInstrumentAspect

public class FooInstrumentAspect extends InstrumentAspect {

    @Pointcut("@annotation(Foo.aop.annotation.FooInstrument)")
    public void FooInstrumentPointcut() {}

    @Around("FooInstrumentPointcut()")
    public Object aroundFooInstrumented(ProceedingJoinPoint pjp) throws Throwable {
        try {
            return aroundInstrumented(pjp);
        } catch (FooStudioException ex) {
            throw ex.getCause();
        }
    }
}

InstrumentAspect

@Aspect
public class InstrumentAspect {

    // 其他代码省略
    @Around("instrumentPointcut()")
    public Object aroundInstrumented(ProceedingJoinPoint pjp) throws Throwable {
        Object result = null;
        Throwable throwable = null;

        try {
            result = pjp.proceed();
        } catch (Throwable t) {
            throwable = t;
        }
        if (throwable != null) {
            throw throwable;
        }

        return result;
    }
}

需求:测试时让pjp.proceed()抛出FooStudioException,同时模拟SpamException的构造方法,避免执行其真实逻辑,使用PowerMock实现。


实现步骤

1. 配置测试类注解

测试类必须添加PowerMock核心注解,指定需要处理的目标类:

@RunWith(PowerMockRunner.class)
@PrepareForTest({SpamException.class, FooStudioException.class})
public class FooInstrumentAspectTest {
    // 测试代码
}
  • @RunWith(PowerMockRunner.class):指定测试用PowerMock运行器执行
  • @PrepareForTest:标记需要被PowerMock拦截构造方法的类,此处包含SpamException和FooStudioException

2. 模拟SpamException构造方法

用PowerMock的whenNew方法拦截SpamException的构造调用,返回模拟对象以跳过真实构造逻辑:

// 创建SpamException模拟实例
SpamException mockSpamEx = Mockito.mock(SpamException.class);

// 模拟带Throwable参数的构造方法
PowerMockito.whenNew(SpamException.class)
            .withArguments(SpamErrorCodes.INTERNAL_ERROR, anyString(), anyString(), any(Throwable.class))
            .thenReturn(mockSpamEx);

// 可选:模拟无Throwable参数的构造方法(根据测试场景需求添加)
PowerMockito.whenNew(SpamException.class)
            .withArguments(SpamErrorCodes.INTERNAL_ERROR, anyString(), anyString())
            .thenReturn(mockSpamEx);

3. 让pjp.proceed()抛出FooStudioException

构造测试用的FooStudioException实例,然后设置ProceedingJoinPoint的proceed方法抛出该异常:

// 创建测试用的异常根因
Throwable testCause = new RuntimeException("测试触发的异常");
// 构造FooStudioException实例
FooStudioException fooEx = new FooStudioException("错误提示", "本地化错误信息", testCause);

// 模拟ProceedingJoinPoint对象
ProceedingJoinPoint pjp = Mockito.mock(ProceedingJoinPoint.class);
// 指定调用proceed时抛出FooStudioException
Mockito.when(pjp.proceed()).thenThrow(fooEx);

4. 执行测试并验证逻辑

调用切面方法,验证是否按预期抛出FooStudioException的根因,同时确认SpamException的构造方法被正确调用:

FooInstrumentAspect aspect = new FooInstrumentAspect();

// 执行切面逻辑,预期会抛出testCause
try {
    aspect.aroundFooInstrumented(pjp);
    Assert.fail("未抛出预期的RuntimeException");
} catch (RuntimeException e) {
    Assert.assertEquals("测试触发的异常", e.getMessage());
}

// 验证SpamException的构造方法是否被调用
PowerMockito.verifyNew(SpamException.class)
            .withArguments(SpamErrorCodes.INTERNAL_ERROR, "错误提示", "本地化错误信息", testCause);

注意事项

  • 若使用JUnit 5,需替换为@ExtendWith(PowerMockExtension.class)替代@RunWith(PowerMockRunner.class)
  • 确保@PrepareForTest包含所有需要模拟构造的类,否则PowerMock无法拦截构造调用
  • 模拟构造方法可隔离SpamException内部的复杂逻辑,保证测试仅关注切面的异常处理逻辑

内容的提问来源于stack exchange,提问作者Abhijit

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 14:20:10