如何用JUnit测试非法输入?处理DateTimeParseException异常
首先得明确:你的测试用例应该预期构造方法在传入无效时间参数时抛出特定异常,而不是走到fail()语句。问题的核心可能有两个:要么你的构造方法没有正确抛出异常(比如try块吞了异常),要么你的测试用例没有正确捕获/预期这个异常。
1. 检查Flight构造方法的异常处理逻辑
从你给出的代码片段看,构造方法里用了try块解析LocalTime,但如果没有对应的catch块,LocalTime.parse()会抛出DateTimeParseException;如果有catch块却没有重新抛出异常,那构造方法就不会向外传递这个错误,导致测试用例无法检测到异常,最终执行fail()。
正确的构造方法做法(应该抛出异常)
如果业务逻辑要求无效时间不能创建Flight对象,那么构造方法应该让异常向外抛出,不要吞掉:
protected Flight(String scheduledTime, String eventType, String identifier) { // 去掉try-catch,让parse的异常直接抛出 this.scheduledTime = LocalTime.parse(scheduledTime); this.eventType = EventType.valueOf(eventType); // 假设EventType是枚举,这里也可能有IllegalArgumentException this.identifier = identifier; }
或者如果必须保留try块,也要在catch里重新抛出异常:
protected Flight(String scheduledTime, String eventType, String identifier) { try { this.scheduledTime = LocalTime.parse(scheduledTime); this.eventType = EventType.valueOf(eventType); this.identifier = identifier; } catch (DateTimeParseException e) { // 重新抛出,或者包装成自定义异常 throw new IllegalArgumentException("Invalid scheduled time format", e); } }
2. 调整JUnit测试用例,预期异常
根据你使用的JUnit版本,有两种写法:
方式一:JUnit 4 使用@Test(expected = ...)
在测试方法上标注预期的异常类型,当构造方法抛出该异常时,测试用例会通过:
@Test(expected = DateTimeParseException.class) public void testConstructor_InvalidScheduledTime() { // 传入无效的时间字符串,比如"25:00"或者"abc" new Flight("25:00", "ARRIVAL", "FL123"); // 如果构造方法正常执行,才会走到这里,此时fail fail("Expected DateTimeParseException was not thrown"); }
注意:如果构造方法抛出的是你自定义的异常(比如IllegalArgumentException),就把expected改成对应的异常类。
方式二:JUnit 5 使用assertThrows()(更推荐)
JUnit 5提供了更灵活的assertThrows方法,可以捕获异常并做进一步验证:
@Test public void testConstructor_InvalidScheduledTime() { // 捕获预期的异常 DateTimeParseException exception = assertThrows(DateTimeParseException.class, () -> { new Flight("25:00", "ARRIVAL", "FL123"); }); // 可选:验证异常信息是否符合预期 assertTrue(exception.getMessage().contains("Invalid value for HourOfDay")); }
这种方式不需要写fail(),因为如果构造方法没有抛出异常,assertThrows会自动让测试失败。
3. 为什么原来的fail()会报错?
因为你的测试用例没有预期异常,当构造方法执行时(如果吞了异常,就会正常创建对象),代码会走到fail()语句,导致测试失败。调整后,要么异常被预期捕获,要么构造方法抛出异常让测试通过。
总结一下步骤:
- 确保Flight构造方法在传入无效时间时会抛出异常(不要吞掉)
- 修改测试用例,使用JUnit的异常预期机制(
@Test(expected)或assertThrows),去掉不必要的fail()或者让fail()只在异常未抛出时执行
内容的提问来源于stack exchange,提问作者Boognish

