了解 JUnit 5 中的异常测试



我已经离开Java一段时间了,在此期间JUnit 5也出现了。我正在尝试将一些现有的 JUnit 4 测试重写为 JUnit 5,但我正在努力处理引发异常的方法。例如,我写了一个名为 LocalizationUtils 的类(不要与 API 中任何其他同名的类混淆(,它有一个名为 getResources(( 的方法,它需要一个非空的基本名称作为输入,如果可以找到,则返回相应的资源包。如果基本名称为 null,则会引发 NullPointerException,如果找不到资源包,则会引发 MissingResourceException。代码如下:

static public ResourceBundle getResources(String baseName) throws NullPointerException, MissingResourceException {
if (baseName == null) {
final String msg = "The base name cannot be null.";
NullPointerException npExcp = new NullPointerException(msg); 
Logger logger = Logger.getLogger(CLASS_NAME);
logger.log(Level.SEVERE, msg, npExcp);
throw npExcp;
}
/* Get the resource bundle for the current locale. */
try {
return(ResourceBundle.getBundle(baseName));
} 
catch (MissingResourceException mrExcp) {
String msg = "Unable to find resources for base name " + baseName + "."; 
Logger logger = Logger.getLogger(CLASS_NAME);
logger.log(Level.SEVERE, msg, mrExcp); 
throw mrExcp;
}
}   

JUnit 5 的手册给出了处理异常的示例:

@Test
void exceptionTesting() {
Throwable exception = assertThrows(IllegalArgumentException.class, () -> {
throw new IllegalArgumentException("a message");
});
assertEquals("a message", exception.getMessage());
}

这个例子对我来说毫无意义。它似乎正在凭空创建一个带有消息"消息"的异常。我根本没有看到它实际上正在执行任何类或方法。没有真正的解释这应该如何工作,所以也许/可能这只是我的误解。

为了尝试编写一个实际执行我的代码并强制发生这两个错误的测试,我编写了以下 JUnit 5 测试:

@Test
void testGetResourcesString() {
//Normal cases
//Exception - input parameter is null
/* Verify that the expected type of exception was thrown. */
Throwable npExcp = assertThrows(NullPointerException.class, () -> {
LocalizationUtils.getResources(null);
});   
/* Verify that the exact right error message was generated. */   
assertEquals("The base name cannot be null.", npExcp.getMessage()); 

//Exception - all input is non-null but resource bundle not found
/* Verify that the expected type of exception was thrown. */
Throwable mrExcp = assertThrows(MissingResourceException.class, () -> {
LocalizationUtils.getResources("foo");
});   
/* Verify that the exact right error message was generated. */
assertEquals("Can't find bundle for base name foo, locale en_CA", mrExcp.getMessage());     
}

此测试中的所有内容都按我的预期工作,并且似乎比手册中的示例更合乎逻辑,因为它实际上执行了一个类和方法来引发异常。我还想确保生成了正确的消息,因为很容易想象一个具有多个输入参数的方法,而不仅仅是一个参数为 null 应该抛出带有唯一消息的异常的方法。仅仅确定抛出了正确的异常对我来说似乎还不够:我觉得我想确保创建了正确的消息,以便我知道代码正在对几个正确的 null 参数做出反应。

不过,我不愿意相信手册是错误的;我想一个由几个经验丰富的开发人员组成的团队编写了它,并且非常小心。任何比我拥有更多 JUnit 5 知识的人(必须几乎是每个曾经使用过 JUnit 5 的人(都可以确认手册中的示例是正确的,如果是,在没有提供类或方法名称时它应该如何工作?

该示例确实调用了"方法"。lambda 表达式() -> {...}定义匿名方法。它包含一个语句:throw new IllegalArgumentException

请参阅 java 语言规范

() -> {}                // No parameters; result is void
() -> 42                // No parameters, expression body
() -> null              // No parameters, expression body
() -> { return 42; }    // No parameters, block body with return
() -> { System.gc(); }  // No parameters, void block body
(int x) -> x+1              // Single declared-type parameter
(int x) -> { return x+1; }  // Single declared-type parameter
(x) -> x+1                  // Single inferred-type parameter
x  -> x+1                  // Parens optional for single inferred-type case

因此,该示例有一个方法,它所做的只是引发异常。

() -> { throw new IllegalArgumentException("a message"); }

在你的代码中,你实际上是在定义一个没有参数的方法,用一个参数调用你的方法。

() -> { LocalizationUtils.getResources(null); } 

最新更新