【发布时间】:2018-10-15 21:36:01
【问题描述】:
我已经离开 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());
}
此测试中的所有内容都按我的预期工作,并且它似乎比手册中的示例更合乎逻辑,因为它实际上执行了一个类和方法来引发异常。我还想确保生成了完全正确的消息,因为很容易想象一个具有多个输入参数的方法,而不是只有一个参数为空的 any 应该抛出带有唯一消息的异常.仅仅确定抛出了正确的异常对我来说似乎还不够:我觉得我想确保创建了正确的消息,以便我知道代码正在对几个正确的 null 参数做出反应。
不过,我不愿意相信手册有误;我想一个由几位经验丰富的开发人员组成的团队编写了它并且非常小心。任何比我了解更多 JUnit 5 知识的人(应该是几乎所有曾经使用过 JUnit 5 的人)都可以确认手册中的示例是否正确,如果正确,那么在没有类或方法名称时它应该如何工作提供?
【问题讨论】:
-
您无中生有地创建异常是正确的。它相当于在测试方法中有
expected = IllegalArgumentException并抛出IllegalArgumentException。唯一的区别是,断言允许您直接检查异常消息(与 JUnit4 不同,您必须创建@Rule) -
在您看来,我的 JUnit 测试代码是对我的 getResource() 方法的公平和充分的测试吗?
-
是的,你测试正确
-
你对
assertThrows()的使用是正确的!对于用户指南中不切实际的示例,我深表歉意。我已经打开了new issue 来解决这个缺点。 -
@Sam Brannen - 感谢您确认我对如何使用 assertThrows() 有正确的理解。我很确定我走在正确的轨道上,但确认总是好的。非常感谢您采取措施实际改进文档!很多时候,我发现文档中的缺点并且不知道如何提出改进建议。 (我的愤世嫉俗的部分想知道是否有任何意义,即使我可以确定如何。)我可以建议进一步改进吗?我正在使用 Eclipse 2018-2019,它还没有提供 JUnit5 测试套件 - 显然没有意图....