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


214

有没有更好的方法来断言方法会在JUnit 5中引发异常?

当前,我必须使用@Rule来验证我的测试抛出异常,但这不适用于我期望多种方法在测试中抛出异常的情况。


1
您可能有兴趣检查AssertJ来检查异常,因为它比JUnit5灵活得多
user1075613

Answers:


323

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

根据JUnit文档

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"));
}

11
从一个古老的学校中“我对Junit5不太了解,对Java8可能还不够了解”……这看起来很奇怪。您介意添加更多解释吗?就像“测试中的实际“生产代码”的哪一部分……应该扔掉”一样?
GhostCat

1
() -> 指向接受零参数的lambda表达式。因此,预期会引发异常的“生产代码”在所指向的代码块(即throw new...大括号内的语句)。
Sam Brannen

1
通常,λ表达将与被测对象(SUT)相互作用。换句话说,直接抛出上述异常只是出于演示目的。
Sam Brannen

1
看起来ExpectThrows已过时。文档说现在改为使用assertThrows()。
depsypher

5
从5.0.0-M4版本开始,expectThrows不再可用。只允许assertThrows。参见github.com/junit-team/junit5/blob/master/documentation/src/docs/…:“为了支持Assertions.assertThrows()而删除了过时的Assertions.expectThrows()方法”
gil.fernandes

91

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

公共静态<T扩展Throwable> T assertThrows(Class <T> ExpectedType,可执行可执行文件)

断言所提供的可执行文件的执行将引发ExpectedType的异常并返回该异常。

如果没有引发异常,或者引发了其他类型的异常,则此方法将失败。

如果您不想对异常实例执行其他检查,则只需忽略返回值。

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

这一方法将使用功能接口Executableorg.junit.jupiter.api

参考:


1
用这个到顶!这是迄今为止最好的答案,它是JUnit 5的最新信息。此外,如果只有一行到Lambda,则IntelliJ会进一步压缩lambda:assertThrows(NoSuchElementException.class, myLinkedList::getFirst);
anon58192932

26

他们已经在JUnit 5中更改了它(预期:InvalidArgumentException,实际:被调用的方法),并且代码如下所示:

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

21

现在,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的示例:断言异常代码示例

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

1
JUnit处理内置和自定义异常的方式没有什么不同。
raindev '19

9

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

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

调用get()包含空值的可选内容ArrayList将引发NoSuchElementExceptionassertThrows声明预期的异常并提供一个lambda供应商(不带参数并返回值)。

感谢@prime的回答,我希望能详细阐述一下。


1
该方法assertThrows返回抛出的异常。因此,您可以像NoSuchElementException e = assertThrows(NoSuchElementException.class, () -> opt2.get());下面所做的那样对所需的异常对象进行任何类型的断言。
曼队长

8

您可以使用assertThrows()。我的示例摘自docs 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());
}

2

一种更简单的衬垫。使用Java 8和JUnit 5的本示例不需要lambda表达式或花括号

import static org.junit.jupiter.api.Assertions.assertThrows;

@Test
void exceptionTesting() {

    assertThrows(MyException.class, myStackObject::doStackAction, "custom message if assertion fails..."); 

// note, no parenthesis on doStackAction ex ::pop NOT ::pop()
}

1

实际上,我认为该特定示例的文档中存在错误。预期的方法是ExpectThrows

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

3
“删除了不推荐使用的Assertions.expectThrows()方法,而改为使用Assertions.assertThrows()。”
马丁·施罗德

对于Junit 5,请确保它来自org.junit.jupiter.api.Assertions,而不是org.testng.Assert。我们的项目同时包含Junit和TestNG,并且我不断获取assertThrows返回void错误,直到将其更改为assertExpects。原来,我在使用org.testng.Assert。
barryku

-5

这是一个简单的方法。

@Test
void exceptionTest() {

   try{
        model.someMethod("invalidInput");
        fail("Exception Expected!");
   }
   catch(SpecificException e){

        assertTrue(true);
   }
   catch(Exception e){
        fail("wrong exception thrown");
   }

}

它仅在引发您期望的异常时成功。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.