JUnit 5:如何断言抛出异常?
Posted
技术标签:
【中文标题】JUnit 5:如何断言抛出异常?【英文标题】:JUnit 5: How to assert an exception is thrown? 【发布时间】:2017-03-09 04:24:42 【问题描述】:在 JUnit 5 中有没有更好的方法来断言方法抛出异常?
目前,我必须使用@Rule 来验证我的测试是否引发了异常,但这不适用于我希望多个方法在我的测试中引发异常的情况。
【问题讨论】:
你可能有兴趣检查 AssertJ 以检查异常,因为它比 JUnit5 更灵活 这是一个在 JUnit4 和 JUnit5 中 how assert that an exception is Thrown 的好例子 如果您期望多个方法在一个测试中抛出异常,那就是代码异味;你可能想编写多个测试,每个抛出一个异常 【参考方案1】:您可以使用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 可能还不够了解”……这看起来很奇怪。您介意添加更多解释吗?比如“其中的哪一部分是正在测试的实际‘生产代码’……应该抛出的”?() ->
points 指向一个接受零参数的 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()'
木星太蹩脚了,迫使我们以这种方式断言信息:-/【参考方案2】:
在 Java 8 和 JUnit 5 (Jupiter) 中,我们可以断言异常如下。
使用org.junit.jupiter.api.Assertions.assertThrows
public static T assertThrows(Class expectedType, 可执行文件)
断言执行所提供的可执行文件会引发预期类型的异常并返回异常。
如果没有抛出异常,或者抛出了不同类型的异常,这个方法就会失败。
如果您不想对异常实例执行额外检查,只需忽略返回值即可。
@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.Executable-【讨论】:
用这个登上顶峰!这是迄今为止最好的答案,它是 JUnit 5 的最新版本。此外,如果 Lambda 只有一行,IntelliJ 会将 lambda 进一步压缩:assertThrows(NoSuchElementException.class, myLinkedList::getFirst);
@anon58192932 这不会发生,因为只有一行,这是因为您只调用一种方法(尽管这自然也只会自动成为一行,除非您有一个长达一英里的方法姓名)。换句话说:object -> object.methodCall()
可以替换为 Object::methodCall
,但您不能将 object -> object.getOneThing().getAnotherThing().doSomething()
替换为方法调用。
感谢 Assertions.assertThrows()。【参考方案3】:
他们在 JUnit 5 中对其进行了更改(预期:InvalidArgumentException,实际:调用方法),代码如下所示:
@Test
public void wrongInput()
Throwable exception = assertThrows(InvalidArgumentException.class,
()->objectName.yourMethod("WRONG"); );
【讨论】:
【参考方案4】:现在 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 处理内置异常和自定义异常的方式没有区别。【参考方案5】:您可以使用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());
【讨论】:
【参考方案6】:TL;DR:如果您使用的是 JUnit 5.8.0+ 版本,则可以使用 assertThrowsExactly()
来匹配确切的异常类型。
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());
【讨论】:
【参考方案7】:我认为这是一个更简单的例子
List<String> emptyList = new ArrayList<>();
Optional<String> opt2 = emptyList.stream().findFirst();
assertThrows(NoSuchElementException.class, () -> opt2.get());
在包含空ArrayList
的可选上调用get()
将抛出NoSuchElementException
。 assertThrows
声明了预期的异常并提供了一个 lambda 供应商(不接受任何参数并返回一个值)。
感谢@prime 的回答,我希望能详细说明。
【讨论】:
方法assertThrows
返回抛出的异常。所以你可以像NoSuchElementException e = assertThrows(NoSuchElementException.class, () -> opt2.get());
那样做,然后你可以在下面对你想要的异常对象做任何类型的断言。【参考方案8】:
更简单的一个班轮。此示例使用 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()
【讨论】:
【参考方案9】:实际上,我认为此特定示例的文档中存在错误。预期的方法是 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。【参考方案10】:这是一个简单的方法。
@Test
void exceptionTest()
try
model.someMethod("invalidInput");
fail("Exception Expected!");
catch(SpecificException e)
assertTrue(true);
catch(Exception e)
fail("wrong exception thrown");
只有当你期望的异常被抛出时才会成功。
【讨论】:
以上是关于JUnit 5:如何断言抛出异常?的主要内容,如果未能解决你的问题,请参考以下文章