异常被try/catch块捕获时,能否通过@Test注解测试主函数是否抛出指定异常?
问题分析与解决方案
首先直接给出结论:你的测试用例永远不会通过,因为maxSum方法内部已经用try/catch捕获了TooMuchException,这个异常完全被方法内部消化了,不会向外部抛出——assertThatThrownBy只能捕获那些从方法中逃逸出来的异常,所以你的断言逻辑从根本上不成立。
为什么会这样?
看你的业务代码:
public int maxSum(int a, int b) { try { if (a + b > 100) throw new TooMuchException("Too much! Sum reduced to 50"); } catch (TooMuchException e) { System.out.println(e); return 50; } return a + b; }
当a+b>100时,确实会抛出TooMuchException,但紧接着就被catch块捕获,方法直接返回50,异常根本不会离开这个方法的作用域。
如何正确测试你的需求?
你的核心需求是:确保函数能捕获异常而不崩溃,同时验证异常触发的逻辑是正确的。可以从以下几个方向入手:
1. 测试返回值(最直接的方式)
既然异常被处理后会返回固定值50,那测试返回值是否符合预期,就能间接验证异常的触发和处理逻辑是正常的:
@Test void maxSum_returns50WhenSumExceeds100() { Service service = new Service(); int result = service.maxSum(55, 66); // 55+66=121>100 assertThat(result).isEqualTo(50); } @Test void maxSum_returnsActualSumWhenSumIsWithinLimit() { Service service = new Service(); int result = service.maxSum(45, 50); // 45+50=95≤100 assertThat(result).isEqualTo(95); }
这种方式简单直接,完全覆盖了你的业务逻辑:当总和超过阈值时,返回50;否则返回实际总和,同时保证程序不会崩溃。
2. 验证异常确实被触发过(如果需要更细粒度的验证)
如果你一定要确认TooMuchException被抛出过(而不只是验证返回值),可以通过给Service类添加状态标记的方式实现:
public class Service { private boolean tooMuchExceptionWasThrown = false; public int maxSum(int a, int b) { tooMuchExceptionWasThrown = false; // 每次调用重置标记 try { if (a + b > 100) throw new TooMuchException("Too much! Sum reduced to 50"); } catch (TooMuchException e) { tooMuchExceptionWasThrown = true; // 标记异常被触发 System.out.println(e); return 50; } return a + b; } // 提供获取标记的方法 public boolean isTooMuchExceptionWasThrown() { return tooMuchExceptionWasThrown; } }
然后编写测试用例验证标记:
@Test void maxSum_triggersTooMuchExceptionWhenSumOver100() { Service service = new Service(); service.maxSum(55, 66); assertThat(service.isTooMuchExceptionWasThrown()).isTrue(); } @Test void maxSum_doesNotTriggerExceptionWhenSumUnder100() { Service service = new Service(); service.maxSum(30, 40); assertThat(service.isTooMuchExceptionWasThrown()).isFalse(); }
3. 小提示:自定义异常的继承选择
你的TooMuchException继承了Throwable,这在Java中非常少见——通常自定义业务异常应该继承Exception(受检异常)或者RuntimeException(非受检异常)。继承Throwable会让你的异常处理逻辑变得繁琐(比如必须显式声明或捕获),建议调整为:
// 作为受检异常 public class TooMuchException extends Exception { public TooMuchException(String message) { super(message); } } // 或者作为非受检异常 public class TooMuchException extends RuntimeException { public TooMuchException(String message) { super(message); } }
内容的提问来源于stack exchange,提问作者Pewu
相关产品推荐
相关产品推荐

