ChatGPT解决这个技术问题 Extra ChatGPT

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

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

目前,我必须使用@Rule 来验证我的测试是否引发了异常,但这不适用于我希望多个方法在我的测试中引发异常的情况。

您可能有兴趣检查 AssertJ 以检查异常,因为它比 JUnit5 更灵活
这是 JUnit4 和 JUnit5 中关于 how assert that an exception is Thrown 的一个很好的示例
如果您期望多个方法在一个测试中引发异常,那是代码异味;您可能想要编写多个测试,一个用于抛出的每个异常

1
12 revs, 8 users 60%

您可以使用 assertThrows(),它允许您在同一个测试中测试多个异常。在 Java 8 中支持 lambda,这是在 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"));
}

来自一个老派的“我对 Junit5 了解不多,对 Java8 可能还不够了解”……这看起来很奇怪。您介意添加更多解释吗?就像“其中的哪个部分是正在测试的实际'生产代码'......应该抛出”?
() -> 指向 接受零参数的 lambda 表达式。因此,预期会引发异常的“生产代码”位于指向的代码块中(即大括号内的throw new... 语句)。
通常,lambda 表达式会与被测对象 (SUT) 交互。换句话说,像上面这样直接抛出异常只是为了演示目的。
从 5.0.0-M4 版开始,expectThrows 不再可用。只允许 assertThrows。请参阅 github.com/junit-team/junit5/blob/master/documentation/src/docs/…:“删除了已弃用的 Assertions.expectThrows() 方法以支持 Assertions.assertThrows()”
木星太蹩脚了,迫使我们以这种方式断言信息:-/
p
prime

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

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

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

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

参考 :

http://junit.org/junit5/docs/current/user-guide/#writing-tests-assertions

http://junit.org/junit5/docs/5.0.0-M2/api/org/junit/jupiter/api/Executable.html

http://junit.org/junit5/docs/5.0.0-M4/api/org/junit/jupiter/api/Assertions.html#assertThrows-java.lang.Class-org.junit.jupiter.api.function。可执行文件-


用这个登顶!这是迄今为止最好的答案,它是 JUnit 5 的最新版本。此外,如果 Lambda 只有一行,IntelliJ 会将 lambda 进一步压缩:assertThrows(NoSuchElementException.class, myLinkedList::getFirst);
@anon58192932 这不会发生,因为只有一行,这是因为您只调用一种方法(尽管这自然也只会自动成为一行,除非您有一个一英里长的方法名称)。换句话说:object -> object.methodCall() 可以替换为 Object::methodCall,但您不能将 object -> object.getOneThing().getAnotherThing().doSomething() 替换为方法调用。
感谢 Assertions.assertThrows()。
j
jstar

他们在 JUnit 5 中对其进行了更改(预期:InvalidArgumentException,实际:调用方法),代码如下所示:

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

A
Anupama Boorlagadda

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

JUnit 处理内置异常和自定义异常的方式没有区别。
G
Govinda Sakhare

TL;DR:如果您使用的是 JUnit 5.8.0+ 版本,则可以使用 assertThrowsExactly() 而不是 assertThrows() 来匹配确切的异常类型。

assertThrowsExactly(FileNotFoundException.class, () -> service.blah());

您可以使用 assertThrows(),但使用 assertThrows,即使抛出的异常是子类型,您的断言也会通过。

这是因为,JUnit 5 通过调用 Class.isIntance(..) 检查异常类型,即使抛出的异常是子类型,Class.isInstance(..) 也会返回 true。

解决方法是在 Class 上断言:

Throwable throwable =  assertThrows(Throwable.class, () -> {
    service.readFile("sampleFile.txt");
});
assertEquals(FileNotFoundException.class, throwable.getClass());

W
Will Humphreys

您可以使用 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());
}

J
John R Perry

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

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

对包含空 ArrayList 的可选项调用 get() 将引发 NoSuchElementExceptionassertThrows 声明了预期的异常并提供了一个 lambda 供应商(不接受任何参数并返回一个值)。

感谢@prime 的回答,我希望能详细说明。


方法 assertThrows 返回抛出的异常。所以你可以像 NoSuchElementException e = assertThrows(NoSuchElementException.class, () -> opt2.get()); 那样做,然后在下面你可以对你想要的异常对象做任何类型的断言。
r
rnyunja

一个更简单的班轮。此示例使用 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()
}

P
Peter

实际上,我认为此特定示例的文档中有错误。预期的方法是 expectThrows

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

“删除了已弃用的 Assertions.expectThrows() 方法以支持 Assertions.assertThrows()。”
对于 Junit 5,确保它来自 org.junit.jupiter.api.Assertions 而不是 org.testng.Assert。我们的项目同时包含 Junit 和 TestNG,并且我一直收到 assertThrows 返回 void 错误,直到我将其更改为 assertExpects。原来我使用的是org.testng.Assert。
I
István D

我的解决方案:

    protected <T extends Throwable> void assertExpectedException(ThrowingRunnable methodExpectedToFail, Class<T> expectedThrowableClass,
        String expectedMessage) {
    T exception = assertThrows(expectedThrowableClass, methodExpectedToFail);
    assertEquals(expectedMessage, exception.getMessage());
}

你可以这样称呼它:

    assertExpectedException(() -> {
        carService.findById(id);
    }, IllegalArgumentException.class, "invalid id");

k
kiwicomb123

这是一个简单的方法。

@Test
void exceptionTest() {

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

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

}

只有当您期望的异常被抛出时,它才会成功。