了解JUnit 5中的异常测试

时间:2018-10-15 21:36:01

标签: java exception junit5

我离开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的方法应该引发带有唯一消息的异常的方法。在我看来,仅仅确定抛出了正确的异常似乎还不够:我觉得我想确保创建了正确的消息,以便我知道代码对几个中的正确null参数做出了反应。

我不愿意相信手册是错误的;我想象一个由几个经验丰富的开发人员组成的团队编写了这个文档,并且非常小心。谁能比我拥有更多JUnit 5知识的人(必须与曾经使用过JUnit 5的所有人差不多)能够确认手册中的示例是正确的,如果是,则在没有类或方法名称的情况下应该如何工作提供了吗?

1 个答案:

答案 0 :(得分:5)

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

Refer to the java language specs

() -> {}                // 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); }