我已经离开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); }