首页 文章

JUnit 5:抛出如何断言异常?

提问于
浏览
104

有没有更好的方法断言方法在JUnit 5中抛出异常?

目前,我必须使用@Rule来验证我的测试是否会引发异常,但这对于我希望多个方法在我的测试中抛出异常的情况不起作用 .

9 回答

  • 151

    您可以使用assertThrows(),它允许您在同一测试中测试多个异常 . 在Java 8中支持lambdas,这是在JUnit中测试异常的规范方法 .

    根据JUnit docs

    import static org.junit.jupiter.api.Assertions.assertThrows;
    
    @Test
    void exceptionTesting() {
        MyException thrown =
            assertThrows(MyException.class,
               () -> myObject.doThing(),
               "Expected doThing() to throw, but it didn't");
    
        assertTrue(thrown.getMessage().contains("Stuff"));
    }
    
  • 0

    在Java 8和JUnit 5(Jupiter)中,我们可以声明异常,如下所示 . 使用 org.junit.jupiter.api.Assertions.assertThrows

    public static <T extends Throwable> T assertThrows(Class <T> expectedType,Executable executable)断言所提供的可执行文件的执行会抛出expectedType的异常并返回异常 . 如果未引发异常,或者抛出了其他类型的异常,则此方法将失败 . 如果您不想对异常实例执行其他检查,只需忽略返回值 .

    @Test
    public void itShouldThrowNullPointerExceptionWhenBlahBlah() {
        assertThrows(NullPointerException.class,
                ()->{
                //do whatever you want to do here
                //ex : objectName.thisMethodShoulThrowNullPointerExceptionForNullParameter(null);
                });
    }
    

    该方法将使用 org.junit.jupiter.api 中的功能接口 Executable .

    参考:

  • 5

    他们在JUnit 5中更改了它(预期:InvalidArgumentException,actual:invoked method),代码如下所示:

    @Test
    public void wrongInput() {
        Throwable exception = assertThrows(InvalidArgumentException.class,
                ()->{objectName.yourMethod("WRONG");} );
    }
    
  • 64

    现在,Junit5提供了一种断言异常的方法

    您可以测试一般例外和自定义例外

    一般异常情况:

    ExpectGeneralException.java

    public void validateParameters(Integer param ) {
        if (param == null) {
            throw new NullPointerException("Null parameters are not allowed");
        }
    }
    

    ExpectGeneralExceptionTest.java

    @Test
    @DisplayName("Test assert NullPointerException")
    void testGeneralException(TestInfo testInfo) {
        final ExpectGeneralException generalEx = new ExpectGeneralException();
    
         NullPointerException exception = assertThrows(NullPointerException.class, () -> {
                generalEx.validateParameters(null);
            });
        assertEquals("Null parameters are not allowed", exception.getMessage());
    }
    

    您可以在此处找到测试CustomException的示例:assert exception code sample

    ExpectCustomException.java

    public String constructErrorMessage(String... args) throws InvalidParameterCountException {
        if(args.length!=3) {
            throw new InvalidParameterCountException("Invalid parametercount: expected=3, passed="+args.length);
        }else {
            String message = "";
            for(String arg: args) {
                message += arg;
            }
            return message;
        }
    }
    

    ExpectCustomExceptionTest.java

    @Test
    @DisplayName("Test assert exception")
    void testCustomException(TestInfo testInfo) {
        final ExpectCustomException expectEx = new ExpectCustomException();
    
         InvalidParameterCountException exception = assertThrows(InvalidParameterCountException.class, () -> {
                expectEx.constructErrorMessage("sample ","error");
            });
        assertEquals("Invalid parametercount: expected=3, passed=2", exception.getMessage());
    }
    
  • 20

    我认为这是一个更简单的例子

    List<String> emptyList = new ArrayList<>();
    Optional<String> opt2 = emptyList.stream().findFirst();
    assertThrows(NoSuchElementException.class, () -> opt2.get());
    

    在包含空 ArrayList 的可选项上调用 get() 将抛出 NoSuchElementException . assertThrows 声明预期的异常并提供lambda供应商(不接受任何参数并返回值) .

    感谢@prime的回答,我希望能够详细阐述 .

  • 6

    你可以使用 assertThrows() . 我的例子取自文档http://junit.org/junit5/docs/current/user-guide/

    import org.junit.jupiter.api.Test;
    
    import static org.junit.jupiter.api.Assertions.assertEquals;
    import static org.junit.jupiter.api.Assertions.assertThrows;
    
    ....
    
    @Test
    void exceptionTesting() {
        Throwable exception = assertThrows(IllegalArgumentException.class, () -> {
            throw new IllegalArgumentException("a message");
        });
        assertEquals("a message", exception.getMessage());
    }
    
  • 13

    实际上我认为这个特定示例的文档中存在错误 . 预期的方法是expectThrows

    public static void assertThrows(
    public static <T extends Throwable> T expectThrows(
    
  • 1

    有三种方法可以在Junit中声明某个异常 . 让我们为它编写单元测试用例 .

    1. try-catch idiom 这个成语是最受欢迎的成语之一,因为它已经在JUnit 3中使用过 . 这种方法是一种常见的模式 . 当没有抛出异常并且在catch子句中验证异常本身时,测试将失败 .

    @Test
    public void convertIntoUpperCase_withInvalidInput_tryCatchIdiom() {
        try {
            exceptionHandling.convertIntoUpperCase("");
            fail("It should throw IllegalArgumentException");
        } catch (IllegalArgumentException e) {
            Assertions.assertThat(e)
                    .isInstanceOf(IllegalArgumentException.class)
                    .hasMessage("Empty value is passed.");
        }
    }
    

    2. @Test expected annotation 在这种方法中,我们在@Test中指定预期的异常,如下所示@Test(expected = IllegalArgumentException.class)

    当没有抛出异常时,您将收到以下消息:java.lang.AssertionError:预期的异常:java.lang.IllegalArgumentException

    使用这种方法,你需要小心 . 有时候很容易期待一般的Exception,RuntimeException甚至是Throwable . 这被认为是一种不好的做法,因为你的代码可能会在实际预期的其他地方抛出异常而你的测试仍然会通过!

    这种方法的缺点之一是您无法断言异常消息 .

    @Test(expected = IllegalArgumentException.class)
    public void convertIntoUpperCase_withInvalidInput_testExpected() {
        exceptionHandling.convertIntoUpperCase("");
    }
    

    3. Junit @Rule 可以使用ExceptedException规则创建相同的示例 . 规则必须是标有@Rule注释的公共字段 .

    @Test
        public void convertIntoUpperCase_withInvalidInput_ExpectedExceptionRule() {
            exception.expect(IllegalArgumentException.class);
            exception.expectMessage("Empty value is passed.");
            exceptionHandling.convertIntoUpperCase("");
        }
    

    我发现上面的代码更具可读性,因此我更喜欢使用这种方法 .

    当没有抛出异常时,您将收到以下消息:java.lang.AssertionError:要抛出的预期测试(java.lang.IllegalArgumentException和异常的实例,并带有消息“传递空值 . ”) . 挺棒的 .

    但不是我用上述方法检查的所有例外情况 . 有时我只需检查抛出的异常类型,然后使用@Test注释 .

  • 1

    这是一个简单的方法 .

    @Test
    void exceptionTest() {
    
       try{
            model.someMethod("invalidInput");
            fail("Exception Expected!");
       }
       catch(SpecificException e){
    
            assertTrue(true);
       }
       catch(Exception e){
            fail("wrong exception thrown");
       }
    
    }
    

    只有在抛出您期望的异常时才会成功 .

相关问题