提问人:SCdF 提问时间:10/1/2008 最后编辑:Arun SudhakaranSCdF 更新时间:8/24/2023 访问量:1876106
您如何断言在 JUnit 测试中抛出某个异常?
How do you assert that a certain exception is thrown in JUnit tests?
问:
如何以惯用的方式使用 JUnit 来测试某些代码是否引发异常?
虽然我当然可以做这样的事情:
@Test
public void testFooThrowsIndexOutOfBoundsException() {
boolean thrown = false;
try {
foo.doStuff();
} catch (IndexOutOfBoundsException e) {
thrown = true;
}
assertTrue(thrown);
}
我记得有一种注释或 Assert.xyz,或者对于这些情况,JUnit 的风格要少得多,而且更符合 JUnit 的精神。
答:
怎么样:捕获一个非常通用的异常,确保它从捕获块中出来,然后断言异常的类是你所期望的。如果 a) 异常类型错误(例如,如果您得到的是 Null 指针),并且 b) 从未抛出异常,则此断言将失败。
public void testFooThrowsIndexOutOfBoundsException() {
Throwable e = null;
try {
foo.doStuff();
} catch (Throwable ex) {
e = ex;
}
assertTrue(e instanceof IndexOutOfBoundsException);
}
评论
assertEquals(ExpectedException.class, e.getClass())
JUnit 对此有内置支持,并具有“预期”属性。
这取决于 JUnit 版本和您使用的断言库。
最初的答案是:JUnit <= 4.12
@Test(expected = IndexOutOfBoundsException.class)
public void testIndexOutOfBoundsException() {
ArrayList emptyList = new ArrayList();
Object o = emptyList.get(0);
}
尽管 answer 为 JUnit <= 4.12 提供了更多选项。
参考:
评论
ArrayList
get()
使用预期异常时要小心,因为它只断言该方法引发了该异常,而不是测试中的特定代码行。
我倾向于使用它来测试参数验证,因为这些方法通常非常简单,但更复杂的测试可能最好使用:
try {
methodThatShouldThrow();
fail( "My method didn't throw when I expected it to" );
} catch (MyException expectedException) {
}
应用判断。
评论
ExpectedException
编辑:现在 JUnit 5 和 JUnit 4.13 已经发布,最好的选择是使用 Assertions.assertThrows() (对于 JUnit 5) 和 Assert.assertThrows() (
对于 JUnit 4.13
+)。有关详细信息,请参阅我的其他答案。
如果您尚未迁移到 JUnit 5,但可以使用 JUnit 4.7,则可以使用 ExpectedException
规则:
public class FooTest {
@Rule
public final ExpectedException exception = ExpectedException.none();
@Test
public void doStuffThrowsIndexOutOfBoundsException() {
Foo foo = new Foo();
exception.expect(IndexOutOfBoundsException.class);
foo.doStuff();
}
}
这比因为如果之前抛出测试会失败要好得多@Test(expected=IndexOutOfBoundsException.class)
IndexOutOfBoundsException
foo.doStuff()
有关详细信息,请参阅此文章。
评论
ExpectedException
为了解决同样的问题,我确实建立了一个小项目:http://code.google.com/p/catch-exception/
使用这个小帮手,你会写
verifyException(foo, IndexOutOfBoundsException.class).doStuff();
这比 JUnit 4.7 的 ExpectedException 规则更详细。 与 skaffman 提供的解决方案相比,您可以指定在哪一行代码中预期异常。我希望这会有所帮助。
评论
foo
final
foo
我在这里尝试了许多方法,但它们要么很复杂,要么不太符合我的要求。事实上,可以非常简单地编写一个辅助方法:
public class ExceptionAssertions {
public static void assertException(BlastContainer blastContainer ) {
boolean caughtException = false;
try {
blastContainer.test();
} catch( Exception e ) {
caughtException = true;
}
if( !caughtException ) {
throw new AssertionFailedError("exception expected to be thrown, but was not");
}
}
public static interface BlastContainer {
public void test() throws Exception;
}
}
像这样使用它:
assertException(new BlastContainer() {
@Override
public void test() throws Exception {
doSomethingThatShouldExceptHere();
}
});
零依赖:不需要mockito,不需要powermock;并且与期末课程配合得很好。
评论
您还可以执行此操作:
@Test
public void testFooThrowsIndexOutOfBoundsException() {
try {
foo.doStuff();
assert false;
} catch (IndexOutOfBoundsException e) {
assert true;
}
}
评论
Assert.fail()
assert
只需制作一个可以关闭和打开的匹配器,如下所示:
public class ExceptionMatcher extends BaseMatcher<Throwable> {
private boolean active = true;
private Class<? extends Throwable> throwable;
public ExceptionMatcher(Class<? extends Throwable> throwable) {
this.throwable = throwable;
}
public void on() {
this.active = true;
}
public void off() {
this.active = false;
}
@Override
public boolean matches(Object object) {
return active && throwable.isAssignableFrom(object.getClass());
}
@Override
public void describeTo(Description description) {
description.appendText("not the covered exception type");
}
}
要使用它,请执行以下操作:
加
然后:public ExpectedException exception = ExpectedException.none();
ExceptionMatcher exMatch = new ExceptionMatcher(MyException.class);
exception.expect(exMatch);
someObject.somethingThatThrowsMyException();
exMatch.off();
就我而言,我总是从 db 获取 RuntimeException,但消息不同。和异常需要分别处理。以下是我测试它的方式:
@Test
public void testThrowsExceptionWhenWrongSku() {
// Given
String articleSimpleSku = "999-999";
int amountOfTransactions = 1;
Exception exception = null;
// When
try {
createNInboundTransactionsForSku(amountOfTransactions, articleSimpleSku);
} catch (RuntimeException e) {
exception = e;
}
// Then
shouldValidateThrowsExceptionWithMessage(exception, MESSAGE_NON_EXISTENT_SKU);
}
private void shouldValidateThrowsExceptionWithMessage(final Exception e, final String message) {
assertNotNull(e);
assertTrue(e.getMessage().contains(message));
}
评论
} catch (
fail("no exception thrown");
BDD的样式解决方案:JUnit 4 + Catch Exception + AssertJ
import static com.googlecode.catchexception.apis.BDDCatchException.*;
@Test
public void testFooThrowsIndexOutOfBoundsException() {
when(() -> foo.doStuff());
then(caughtException()).isInstanceOf(IndexOutOfBoundsException.class);
}
依赖
eu.codearte.catch-exception:catch-exception:2.0
如前所述,在 JUnit 中有很多方法可以处理异常。但是在 Java 8 中还有另一个:使用 Lambda 表达式。使用 Lambda 表达式,我们可以实现如下语法:
@Test
public void verifiesTypeAndMessage() {
assertThrown(new DummyService()::someMethod)
.isInstanceOf(RuntimeException.class)
.hasMessage("Runtime exception occurred")
.hasMessageStartingWith("Runtime")
.hasMessageEndingWith("occurred")
.hasMessageContaining("exception")
.hasNoCause();
}
assertThrown 接受函数接口,可以使用 lambda 表达式、方法引用或构造函数引用创建其实例。assertThrown 接受该接口将期望并准备好处理异常。
这是一种相对简单但强大的技术。
看看这篇描述这种技术的博客文章:http://blog.codeleak.pl/2014/07/junit-testing-exception-with-java-8-and-lambda-expressions.html
披露:我是博客和项目的作者。
评论
new DummyService()::someMethod
MethodHandle
我们可以在必须返回异常的方法之后使用断言失败:
try{
methodThatThrowMyException();
Assert.fail("MyException is not thrown !");
} catch (final Exception exception) {
// Verify if the thrown exception is instance of MyException, otherwise throws an assert failure
assertTrue(exception instanceof MyException, "An exception other than MyException is thrown !");
// In case of verifying the error message
MyException myException = (MyException) exception;
assertEquals("EXPECTED ERROR MESSAGE", myException.getMessage());
}
评论
catch
恕我直言,在 JUnit 中检查异常的最佳方法是 try/catch/fail/assert 模式:
// this try block should be as small as possible,
// as you want to make sure you only catch exceptions from your code
try {
sut.doThing();
fail(); // fail if this does not throw any exception
} catch(MyException e) { // only catch the exception you expect,
// otherwise you may catch an exception for a dependency unexpectedly
// a strong assertion on the message,
// in case the exception comes from anywhere an unexpected line of code,
// especially important if your checking IllegalArgumentExceptions
assertEquals("the message I get", e.getMessage());
}
对于某些人来说,这可能有点强,所以可能更可取。assertTrue
assertThat(e.getMessage(), containsString("the message");
除了 NamShubWriter 所说的之外,请确保:
请勿这样做:
@Rule
public ExpectedException expectedException;
@Before
public void setup()
{
expectedException = ExpectedException.none();
}
最后,这篇博文清楚地说明了如何断言抛出某个异常。
在 JUNIT 中,有四种方法可以测试异常。
JUNIT5.x
对于 JUNIT5.x,您可以按以下方式使用
assertThrows
@Test public void testFooThrowsIndexOutOfBoundsException() { Throwable exception = assertThrows(IndexOutOfBoundsException.class, () -> foo.doStuff()); assertEquals("expected messages", exception.getMessage()); }
朱尼特4.x
对于 junit4.x,请使用测试 annonation 的可选“expected”属性
@Test(expected = IndexOutOfBoundsException.class) public void testFooThrowsIndexOutOfBoundsException() { foo.doStuff(); }
对于 junit4.x,请使用 ExpectedException 规则
public class XxxTest { @Rule public ExpectedException thrown = ExpectedException.none(); @Test public void testFooThrowsIndexOutOfBoundsException() { thrown.expect(IndexOutOfBoundsException.class) //you can test the exception message like thrown.expectMessage("expected messages"); foo.doStuff(); } }
您还可以使用 JUn 3 框架下广泛使用的经典 try/catch 方式
@Test public void testFooThrowsIndexOutOfBoundsException() { try { foo.doStuff(); fail("expected exception was not occured."); } catch(IndexOutOfBoundsException e) { //if execution reaches here, //it indicates this exception was occured. //so we need not handle it. } }
所以
- 如果你喜欢 junit 5,那么你应该喜欢第一个
- 当您只想测试异常类型时,使用第二种方式
- 当您需要进一步测试异常消息时,将使用第一个和最后一个
- 如果使用 JUNIT 3,则首选第 4 个
有关详细信息,您可以阅读此文档和 JUnit5 用户指南了解详细信息。
评论
Java 8 解决方案
如果您想要一个解决方案:
- 利用 Java 8 lambda
- 不依赖于任何 JUnit 魔法
- 允许您检查单个测试方法中的多个异常
- 检查测试方法中的一组特定行引发的异常,而不是整个测试方法中的任何未知行
- 生成引发的实际异常对象,以便您可以进一步检查它
这是我写的一个实用函数:
public final <T extends Throwable> T expectException( Class<T> exceptionClass, Runnable runnable )
{
try
{
runnable.run();
}
catch( Throwable throwable )
{
if( throwable instanceof AssertionError && throwable.getCause() != null )
throwable = throwable.getCause(); //allows testing for "assert x != null : new IllegalArgumentException();"
assert exceptionClass.isInstance( throwable ) : throwable; //exception of the wrong kind was thrown.
assert throwable.getClass() == exceptionClass : throwable; //exception thrown was a subclass, but not the exact class, expected.
@SuppressWarnings( "unchecked" )
T result = (T)throwable;
return result;
}
assert false; //expected exception was not thrown.
return null; //to keep the compiler happy.
}
(摘自我的博客)
按如下方式使用:
@Test
public void testMyFunction()
{
RuntimeException e = expectException( RuntimeException.class, () ->
{
myFunction();
} );
assert e.getMessage().equals( "I haz fail!" );
}
public void myFunction()
{
throw new RuntimeException( "I haz fail!" );
}
使用 AssertJ 断言,该断言可以与 JUnit 一起使用:
import static org.assertj.core.api.Assertions.*;
@Test
public void testFooThrowsIndexOutOfBoundsException() {
Foo foo = new Foo();
assertThatThrownBy(() -> foo.doStuff())
.isInstanceOf(IndexOutOfBoundsException.class);
}
它比因为它保证测试中的预期行抛出异常,并让您更轻松地检查有关异常的更多详细信息(例如消息)更好:@Test(expected=IndexOutOfBoundsException.class)
assertThatThrownBy(() ->
{
throw new Exception("boom!");
})
.isInstanceOf(Exception.class)
.hasMessageContaining("boom");
评论
assertThat
AbstractAssert
JUnit 5 解决方案
import static org.junit.jupiter.api.Assertions.assertThrows;
@Test
void testFooThrowsIndexOutOfBoundsException() {
IndexOutOfBoundsException exception = expectThrows(IndexOutOfBoundsException.class, foo::doStuff);
assertEquals("some message", exception.getMessage());
}
有关 JUnit 5 的更多信息 http://junit.org/junit5/docs/current/user-guide/#writing-tests-assertions
评论
expectThrows()
是 TestNG 的一部分,而不是 JUnit
举个例子,你想为下面提到的代码片段编写 Junit
public int divideByZeroDemo(int a,int b){
return a/b;
}
public void exceptionWithMessage(String [] arr){
throw new ArrayIndexOutOfBoundsException("Array is out of bound");
}
上面的代码是测试可能发生的一些未知异常,下面的代码是用自定义消息断言一些异常。
@Rule
public ExpectedException exception=ExpectedException.none();
private Demo demo;
@Before
public void setup(){
demo=new Demo();
}
@Test(expected=ArithmeticException.class)
public void testIfItThrowsAnyException() {
demo.divideByZeroDemo(5, 0);
}
@Test
public void testExceptionWithMessage(){
exception.expectMessage("Array is out of bound");
exception.expect(ArrayIndexOutOfBoundsException.class);
demo.exceptionWithMessage(new String[]{"This","is","a","demo"});
}
TL的;博士
post-JDK8 :使用 AssertJ 或自定义 lambda 来断言异常行为。
pre-JDK8 :我会推荐旧的好 - 块。(别忘了在
catch
块之前添加一个 fail()
断言try
catch
)
无论是 Junit 4 还是 JUnit 5。
长话短说
可以自己编写一个自己动手 - 阻止或使用 JUnit 工具(或 JUnit 规则功能)。try
catch
@Test(expected = ...)
@Rule ExpectedException
但这些方法并不那么优雅,并且不能很好地与其他工具混合使用。此外,JUnit 工具确实存在一些缺陷。
- 块,您必须围绕测试的行为编写块,并在 catch 块中写入断言,这可能很好,但许多人发现这种样式会中断测试的读取流程。此外,您需要在块的末尾写一个。否则,测试可能会遗漏断言的一侧;PMD、findbugs 或 Sonar 会发现此类问题。
try
catch
Assert.fail
try
这个功能很有趣,因为你可以写更少的代码,然后编写这个测试应该不容易出现编码错误。但这种方法在某些领域是缺乏的。
@Test(expected = ...)
- 如果测试需要检查异常的其他内容,例如原因或消息(好的异常消息非常重要,但拥有精确的异常类型可能还不够)。
此外,由于期望被放置在方法中,具体取决于测试代码的编写方式,那么测试代码的错误部分可能会引发异常,导致误报测试,我不确定 PMD、findbugs 或 Sonar 是否会对此类代码给出提示。
@Test(expected = WantedException.class) public void call2_should_throw_a_WantedException__not_call1() { // init tested tested.call1(); // may throw a WantedException // call to be actually tested tested.call2(); // the call that is supposed to raise an exception }
该规则也是修复先前警告的尝试,但是使用起来感觉有点尴尬,因为它使用了期望样式,EasyMock用户非常了解这种样式。这对某些人来说可能很方便,但如果你遵循行为驱动开发 (BDD) 或安排行为断言 (AAA) 原则,该规则将不适合这些写作风格。除此之外,它可能会遇到与方式相同的问题,具体取决于您期望的位置。
ExpectedException
ExpectedException
@Test
@Rule ExpectedException thrown = ExpectedException.none() @Test public void call2_should_throw_a_WantedException__not_call1() { // expectations thrown.expect(WantedException.class); thrown.expectMessage("boom"); // init tested tested.call1(); // may throw a WantedException // call to be actually tested tested.call2(); // the call that is supposed to raise an exception }
即使预期的异常放在测试语句之前,如果测试遵循 BDD 或 AAA,它也会中断您的读取流程。
另外,请参阅作者在 JUnit 上的此评论问题。JUnit 4.13-beta-2 甚至弃用了这种机制:
ExpectedException
拉取请求 #1519:弃用 ExpectedException
Assert.assertThrows 方法提供了一种更好的方法来验证异常。此外,当与其他规则(如 TestWatcher)一起使用时,使用 ExpectedException 很容易出错,因为在这种情况下,规则的顺序很重要。
因此,上述这些选项都有其所有警告,并且显然不能幸免于编码人员错误。
在创建这个看起来很有希望的答案后,我意识到了一个项目,它是陷阱例外。
正如项目描述所说,它允许编码人员用流畅的代码行来捕获异常,并为后一个断言提供此异常。您可以使用任何断言库,如 Hamcrest 或 AssertJ。
从主页上获取的快速示例:
// given: an empty list List myList = new ArrayList(); // when: we try to get the first element of the list when(myList).get(1); // then: we expect an IndexOutOfBoundsException then(caughtException()) .isInstanceOf(IndexOutOfBoundsException.class) .hasMessage("Index: 1, Size: 0") .hasNoCause();
正如你所看到的,代码非常简单,你在特定行上捕获异常,API 是一个别名,它将使用 AssertJ API(类似于使用 )。在某种程度上,该项目依赖于 AssertJ 的祖先 FEST-Assert。编辑:该项目似乎正在酝酿对 Java 8 Lambdas 的支持。
then
assertThat(ex).hasNoCause()...
目前,该库有两个缺点:
在撰写本文时,值得注意的是,该库基于 Mockito 1.x,因为它在幕后创建了测试对象的模拟。由于 Mockito 仍未更新,因此该库无法与最终类或最终方法一起使用。即使它基于当前版本中的 Mockito 2,这也需要声明一个全局模拟制作者 (),这可能不是你想要的,因为这个模拟制作者与常规模拟制作者具有不同的缺点。
inline-mock-maker
它需要另一个测试依赖项。
一旦库支持 lambda,这些问题将不适用。但是,AssertJ 工具集将复制该功能。
考虑到所有因素,如果您不想使用 catch-exception 工具,我会推荐
try-catch
块的旧方法,至少到 JDK7。对于 JDK 8 用户,您可能更喜欢使用 AssertJ,因为它提供的可能不仅仅是断言异常。
随着 JDK8 的推出,lambda 进入了测试场景,它们已被证明是一种维护卓越行为的有趣方式。AssertJ 已更新,以提供一个很好的流畅 API 来断言异常行为。
以及使用 AssertJ 的示例测试:
@Test public void test_exception_approach_1() { ... assertThatExceptionOfType(IOException.class) .isThrownBy(() -> someBadIOOperation()) .withMessage("boom!"); } @Test public void test_exception_approach_2() { ... assertThatThrownBy(() -> someBadIOOperation()) .isInstanceOf(Exception.class) .hasMessageContaining("boom"); } @Test public void test_exception_approach_3() { ... // when Throwable thrown = catchThrowable(() -> someBadIOOperation()); // then assertThat(thrown).isInstanceOf(Exception.class) .hasMessageContaining("boom"); }
随着对 JUnit 5 的近乎完全的重写,断言得到了一些改进,它们可能被证明是一种开箱即用的正确断言异常的方法。但实际上断言 API 还是有点差,
assertThrows
之外什么都没有。@Test @DisplayName("throws EmptyStackException when peeked") void throwsExceptionWhenPeeked() { Throwable t = assertThrows(EmptyStackException.class, () -> stack.peek()); Assertions.assertEquals("...", t.getMessage()); }
正如你所注意到的,它仍然返回,因此不允许像 AssertJ 这样的链接断言。
assertEquals
void
此外,如果您记得名称与 或 的冲突,请准备好遇到与 相同的冲突。
Matcher
Assert
Assertions
我想总结一下,今天(2017-03-03)AssertJ 的易用性、可发现的 API、快速的开发速度以及作为事实上的测试依赖是 JDK8 的最佳解决方案,无论测试框架如何(是否是 JUnit),以前的 JDK 应该依赖 try-catch
块,即使它们感觉笨拙。
这个答案是从另一个没有相同可见性的问题中复制的,我是同一个作者。
评论
在 JUnit 4 或更高版本中,您可以按如下方式测试异常
@Rule
public ExpectedException exceptions = ExpectedException.none();
这提供了许多可用于改进 JUnit 测试的功能。
如果您看到下面的示例,我正在测试异常的 3 件事。
- 引发的异常类型
- 异常消息
- 异常的原因
public class MyTest {
@Rule
public ExpectedException exceptions = ExpectedException.none();
ClassUnderTest classUnderTest;
@Before
public void setUp() throws Exception {
classUnderTest = new ClassUnderTest();
}
@Test
public void testAppleisSweetAndRed() throws Exception {
exceptions.expect(Exception.class);
exceptions.expectMessage("this is the exception message");
exceptions.expectCause(Matchers.<Throwable>equalTo(exceptionCause));
classUnderTest.methodUnderTest("param1", "param2");
}
}
更新:JUnit5 对异常测试进行了改进:。assertThrows
以下示例来自:Junit 5 用户指南
import static org.junit.jupiter.api.Assertions.assertThrows;
@Test
void exceptionTesting() {
IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> {
throw new IllegalArgumentException("a message");
});
assertEquals("a message", exception.getMessage());
}
使用 JUnit 4 的原始答案。
有几种方法可以测试是否引发了异常。我还在我的帖子中讨论了以下选项 如何使用 JUnit 编写出色的单元测试
设置参数 。expected
@Test(expected = FileNotFoundException.class)
@Test(expected = FileNotFoundException.class)
public void testReadFile() {
myClass.readFile("test.txt");
}
用try
catch
public void testReadFile() {
try {
myClass.readFile("test.txt");
fail("Expected a FileNotFoundException to be thrown");
} catch (FileNotFoundException e) {
assertThat(e.getMessage(), is("The file test.txt does not exist!"));
}
}
使用 Rule 进行测试。ExpectedException
@Rule
public ExpectedException thrown = ExpectedException.none();
@Test
public void testReadFile() throws FileNotFoundException {
thrown.expect(FileNotFoundException.class);
thrown.expectMessage(startsWith("The file test.txt"));
myClass.readFile("test.txt");
}
您可以在 JUnit4 wiki 的异常测试和 bad.robot - 期待异常 JUnit 规则中阅读有关异常测试的更多信息。
在 Java 8 中,您可以创建一个方法,将要检查的代码和预期的异常作为参数:
private void expectException(Runnable r, Class<?> clazz) {
try {
r.run();
fail("Expected: " + clazz.getSimpleName() + " but not thrown");
} catch (Exception e) {
if (!clazz.isInstance(e)) fail("Expected: " + clazz.getSimpleName() + " but " + e.getClass().getSimpleName() + " found", e);
}
}
然后在测试中:
expectException(() -> list.sublist(0, 2).get(2), IndexOutOfBoundsException.class);
好处:
- 不依赖任何图书馆
- 本地化检查 - 更精确,如果需要,允许在一次测试中进行多个这样的断言
- 简单易用
现在 JUnit 5 和 JUnit 4.13 已经发布,最好的选择是使用 (对于 JUnit 5) 和 (对于 JUnit 4.13)。看
《JUnit 5 用户指南》。Assertions.assertThrows()
Assert.assertThrows()
下面是一个示例,用于验证是否引发了异常,并使用 Truth 对异常消息进行断言:
public class FooTest {
@Test
public void doStuffThrowsIndexOutOfBoundsException() {
Foo foo = new Foo();
IndexOutOfBoundsException e = assertThrows(
IndexOutOfBoundsException.class, foo::doStuff);
assertThat(e).hasMessageThat().contains("woops!");
}
}
与其他答案中的方法相比,其优点是:
- 内置于 JUnit 中
- 如果 lambda 中的代码未引发异常,您将收到一条有用的异常消息,如果引发其他异常,则会收到堆栈跟踪
- 简明
- 允许您的测试遵循 Arrange-Act-Assert
- 您可以精确地指出您期望抛出异常的代码
- 您不需要在子句中列出预期的例外
throws
- 您可以使用所选的断言框架对捕获的异常进行断言
评论
我在 Mkyong 博客中找到的 Junit 4 最灵活、最优雅的答案。它具有使用注释的灵活性。我喜欢这种方法,因为您可以读取自定义异常的特定属性。try/catch
@Rule
package com.mkyong;
import com.mkyong.examples.CustomerService;
import com.mkyong.examples.exception.NameNotFoundException;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.Matchers.hasProperty;
public class Exception3Test {
@Rule
public ExpectedException thrown = ExpectedException.none();
@Test
public void testNameNotFoundException() throws NameNotFoundException {
//test specific type of exception
thrown.expect(NameNotFoundException.class);
//test message
thrown.expectMessage(is("Name is empty!"));
//test detail
thrown.expect(hasProperty("errCode")); //make sure getters n setters are defined.
thrown.expect(hasProperty("errCode", is(666)));
CustomerService cust = new CustomerService();
cust.findByName("");
}
}
带有 Java8 的 Junit4 解决方案是使用这个函数:
public Throwable assertThrows(Class<? extends Throwable> expectedException, java.util.concurrent.Callable<?> funky) {
try {
funky.call();
} catch (Throwable e) {
if (expectedException.isInstance(e)) {
return e;
}
throw new AssertionError(
String.format("Expected [%s] to be thrown, but was [%s]", expectedException, e));
}
throw new AssertionError(
String.format("Expected [%s] to be thrown, but nothing was thrown.", expectedException));
}
然后用法是:
assertThrows(ValidationException.class,
() -> finalObject.checkSomething(null));
请注意,唯一的限制是在 lambda 表达式中使用对象引用。
此解决方案允许继续测试断言,而不是期望使用解决方案在方法级别进行 thowable。final
@Test(expected = IndexOutOfBoundsException.class)
我建议库在junit测试中处理异常assertj-core
在 java 8 中,如下所示:
//given
//when
Throwable throwable = catchThrowable(() -> anyService.anyMethod(object));
//then
AnyException anyException = (AnyException) throwable;
assertThat(anyException.getMessage()).isEqualTo("........");
assertThat(exception.getCode()).isEqualTo(".......);
@Test(expectedException=IndexOutOfBoundsException.class)
public void testFooThrowsIndexOutOfBoundsException() throws Exception {
doThrow(IndexOutOfBoundsException.class).when(foo).doStuff();
try {
foo.doStuff();
} catch (IndexOutOfBoundsException e) {
assertEquals(IndexOutOfBoundsException .class, ex.getCause().getClass());
throw e;
}
}
这是检查方法是否抛出正确异常的另一种方法。
JUnit 框架有 assertThrows()
方法:
ArithmeticException exception = assertThrows(ArithmeticException.class, () ->
calculator.divide(1, 0));
assertEquals("/ by zero", exception.getMessage());
- 对于 JUnit 5,它位于
org.junit.jupiter.api.Assertions
类中; - 对于 JUnit 4.13,它位于
org.junit.Assert
类中; - 对于早期版本的 JUnit 4:只需将
org.junit.jupiter:junit-jupiter-api
上的引用添加到您的项目中,您就可以从 JUnit 5 获得完美的工作版本。
评论
org.mockito.Mockito.verify