您如何断言在JUnit测试中抛出某个异常?

如何习惯地使用JUnit来测试某些代码是否抛出异常?

我当然可以做这样的事情:

@Testpublic void testFooThrowsIndexOutOfBoundsException() {boolean thrown = false;
try {foo.doStuff();} catch (IndexOutOfBoundsException e) {thrown = true;}
assertTrue(thrown);}

我记得有一个注释或Assert.xyz或东西,对于这些情况来说,它远没有那么笨拙,更符合JUnit的精神。

1717246 次浏览

这样如何:捕获一个非常一般的异常,确保它从catch块中出来,然后断言异常的类是你期望的。如果a)异常类型错误(例如,如果你得到了空指针)和b)异常从未抛出,此断言将失败。

public void testFooThrowsIndexOutOfBoundsException() {Throwable e = null;
try {foo.doStuff();} catch (Throwable ex) {e = ex;}
assertTrue(e instanceof IndexOutOfBoundsException);}

JUnit对此有内置支持,带有“预期”属性

这取决于JUnit版本以及您使用的断言库。

JUnit <= 4.12的原始答案是:

    @Test(expected = IndexOutOfBoundsException.class)public void testIndexOutOfBoundsException() {
ArrayList emptyList = new ArrayList();Object o = emptyList.get(0);
}

尽管回答对JUnit<=4.12有更多选项。

参考:

使用预期异常时要小心,因为它只断言方法抛出了该异常,而不是测试中的特定的代码行

我倾向于使用它来测试参数校验,因为这些方法通常非常简单,但更复杂的测试可能更好:

try {methodThatShouldThrow();fail( "My method didn't throw when I expected it to" );} catch (MyException expectedException) {}

适用判断。

编辑:现在JUnit 5和JUnit 4.13已经发布,最好的选择是使用#0(用于JUnit 5)和#1(用于JUnit 4.13+)。有关详细信息,请参阅我的另一个答案

如果你还没有迁移到JUnit 5,但可以使用JUnit 4.7,你可以使用#0规则:

public class FooTest {@Rulepublic final ExpectedException exception = ExpectedException.none();
@Testpublic void doStuffThrowsIndexOutOfBoundsException() {Foo foo = new Foo();
exception.expect(IndexOutOfBoundsException.class);foo.doStuff();}}

这比@Test(expected=IndexOutOfBoundsException.class)好得多,因为如果IndexOutOfBoundsExceptionfoo.doStuff()之前抛出,测试将失败

详情见这篇文章

为了解决这个问题,我做了一个小项目:http://code.google.com/p/catch-exception/

使用这个小助手你会写

verifyException(foo, IndexOutOfBoundsException.class).doStuff();

这比JUnit 4.7的期望异常规则要少。与skaffman提供的解决方案相比,您可以指定您期望异常的代码行。我希望这有帮助。

我尝试了这里的许多方法,但它们要么很复杂,要么不太符合我的要求。事实上,可以很简单地编写一个helper方法:

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() {@Overridepublic void test() throws Exception {doSomethingThatShouldExceptHere();}});

零依赖:不需要mockito,不需要Powermock;并且与最终类一起工作得很好。

你也可以这样做:

@Testpublic void testFooThrowsIndexOutOfBoundsException() {try {foo.doStuff();assert false;} catch (IndexOutOfBoundsException e) {assert true;}}

只需制作一个可以关闭和打开的Matcher,就像这样:

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;}
@Overridepublic boolean matches(Object object) {return active && throwable.isAssignableFrom(object.getClass());}
@Overridepublic 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,但消息不同。需要分别处理异常。这是我测试它的方式:

@Testpublic void testThrowsExceptionWhenWrongSku() {
// GivenString articleSimpleSku = "999-999";int amountOfTransactions = 1;Exception exception = null;
// Whentry {createNInboundTransactionsForSku(amountOfTransactions, articleSimpleSku);} catch (RuntimeException e) {exception = e;}
// ThenshouldValidateThrowsExceptionWithMessage(exception, MESSAGE_NON_EXISTENT_SKU);}
private void shouldValidateThrowsExceptionWithMessage(final Exception e, final String message) {assertNotNull(e);assertTrue(e.getMessage().contains(message));}

BDD风格解决方案:JUnit 4+捕获异常+AssertJ

import static com.googlecode.catchexception.apis.BDDCatchException.*;
@Testpublic void testFooThrowsIndexOutOfBoundsException() {
when(() -> foo.doStuff());
then(caughtException()).isInstanceOf(IndexOutOfBoundsException.class);
}

依赖关系

eu.codearte.catch-exception:catch-exception:2.0

如前所述,在JUnit中有很多处理异常的方法。但是Java8还有另一种方法:使用Lambda表达式。使用Lambda表达式,我们可以实现这样的语法:

@Testpublic void verifiesTypeAndMessage() {assertThrown(new DummyService()::someMethod).isInstanceOf(RuntimeException.class).hasMessage("Runtime exception occurred").hasMessageStartingWith("Runtime").hasMessageEndingWith("occurred").hasMessageContaining("exception").hasNoCause();}

断言抛出接受一个函数式接口,其实例可以使用lambda表达式、方法引用或构造函数引用创建。断言抛出接受该接口将期望并准备好处理异常。

这是一种相对简单但功能强大的技术。

看看这篇描述这种技术的博客文章:http://blog.codeleak.pl/2014/07/junit-testing-exception-with-java-8-and-lambda-expressions.html

源代码可以在这里找到:https://github.com/kolorobot/unit-testing-demo/tree/master/src/test/java/com/github/kolorobot/exceptions/java8

披露:我是博客和项目的作者。

我们可以在必须返回异常的方法之后使用断言失败:

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 failureassertTrue(exception instanceof MyException, "An exception other than MyException is thrown !");// In case of verifying the error messageMyException myException = (MyException) exception;assertEquals("EXPECTED ERROR MESSAGE", myException.getMessage());}

恕我直言,在JUnit中检查异常的最佳方法是try/catch/失败/断言模式:

// this try block should be as small as possible,// as you want to make sure you only catch exceptions from your codetry {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 IllegalArgumentExceptionsassertEquals("the message I get", e.getMessage());}

对于某些人来说,assertTrue可能有点强,所以assertThat(e.getMessage(), containsString("the message");可能更可取。

除了应用名称所说的,请确保:

  • 公共相关问题)的实例
  • EXECTEDException不是实例化了@在方法中。这帖子清楚地解释了JUnit执行顺序的所有复杂性。

没有这样做:

@Rulepublic ExpectedException expectedException;
@Beforepublic void setup(){expectedException = ExpectedException.none();}

最后,这个博客文章清楚地说明了如何断言抛出某个异常。

在jUnit中,有四种方法来测试异常。

juit5. x

  • 对于Junit5. x,您可以使用assertThrows如下

    @Testpublic void testFooThrowsIndexOutOfBoundsException() {Throwable exception = assertThrows(IndexOutOfBoundsException.class, () -> foo.doStuff());assertEquals("expected messages", exception.getMessage());}

junit4.x

  • for junit4.x, use the optional 'expected' attribute of Test annonation

    @Test(expected = IndexOutOfBoundsException.class)public void testFooThrowsIndexOutOfBoundsException() {foo.doStuff();}
  • for junit4.x, use the ExpectedException rule

    public class XxxTest {@Rulepublic ExpectedException thrown = ExpectedException.none();
    @Testpublic void testFooThrowsIndexOutOfBoundsException() {thrown.expect(IndexOutOfBoundsException.class)//you can test the exception message likethrown.expectMessage("expected messages");foo.doStuff();}}
  • you also can use the classic try/catch way widely used under junit 3 framework

    @Testpublic 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.}}
  • so

    • if you like junit 5, then you should like the 1st one
    • the 2nd way is used when you only want test the type of exception
    • the first and last two are used when you want test exception message further
    • if you use junit 3, then the 4th one is preferred
  • for more info, you can read this document and junit5 user guide for details.

Java8解决方案

如果你想要一个解决方案:

  • 使用Java8 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.}

摘自我的博客

使用它如下:

@Testpublic 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.*;
@Testpublic 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");

Maven/Gradle指令在这里。

我想评论一下我对这个问题的解决方案,它避免了需要任何与异常相关的JUnit代码。

我使用assertTrue(boolean)结合try/catch来查找要抛出的预期异常。这是一个例子:

public void testConstructor() {boolean expectedExceptionThrown;try {// Call constructor with bad argumentsdouble a = 1;double b = 2;double c = a + b; // In my example, this is an invalid option for cnew Triangle(a, b, c);expectedExceptionThrown = false; // because it successfully constructed the object}catch(IllegalArgumentException e) {expectedExceptionThrown = true; // because I'm in this catch block}catch(Exception e) {expectedExceptionThrown = false; // because it threw an exception but not the one expected}assertTrue(expectedExceptionThrown);}

JUnit 5解决方案

import static org.junit.jupiter.api.Assertions.assertThrows;
@Testvoid 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

例如,您想为下面提到的代码片段编写JUnit

public int divideByZeroDemo(int a,int b){
return a/b;}
public void exceptionWithMessage(String [] arr){
throw new ArrayIndexOutOfBoundsException("Array is out of bound");}

上面的代码是测试可能发生的一些未知异常,下面的代码是使用自定义消息断言一些异常。

 @Rulepublic ExpectedException exception=ExpectedException.none();
private Demo demo;@Beforepublic void setup(){
demo=new Demo();}@Test(expected=ArithmeticException.class)public void testIfItThrowsAnyException() {
demo.divideByZeroDemo(5, 0);
}
@Testpublic void testExceptionWithMessage(){

exception.expectMessage("Array is out of bound");exception.expect(ArrayIndexOutOfBoundsException.class);demo.exceptionWithMessage(new String[]{"This","is","a","demo"});}

tl; dr

  • 后JDK8:使用AssertJ或自定义lambda来断言异常行为。

  • pre-JDK8:我会推荐旧的好try-catch块。(不要忘记在catch之前添加fail()断言)

无论是JUnit 4还是JUnit 5。

的漫长故事

可以自己编写你自己动手吧try-catch块或使用JUnit工具(@Test(expected = ...)@Rule ExpectedException JUnit规则功能)。

但是这些方法不是那么优雅,并且不能很好地将易读性与其他工具混合。此外,JUnit工具确实存在一些缺陷。

  1. try-catch块中,您必须围绕测试行为编写块并在catch块中写入断言,这可能没问题,但许多人发现这种风格会中断测试的读取流程。此外,您需要在try块的末尾编写Assert.fail。否则,测试可能会遗漏断言的一面;PMDfindbugsSonar会发现此类问题。

  2. @Test(expected = ...)特性很有趣,因为您可以编写更少的代码,然后编写此测试据说不太容易出现编码错误。但是这种方法在某些领域缺乏。

    • 如果测试需要检查异常的其他内容,例如原因或消息(良好的异常消息非常重要,拥有精确的异常类型可能还不够)。
    • 同样,由于期望被放置在方法中,根据测试代码的编写方式,测试代码的错误部分可能会抛出异常,导致假阳性测试,我不确定PMD查找错误声纳是否会给出此类代码的提示。

      @Test(expected = WantedException.class)public void call2_should_throw_a_WantedException__not_call1() {// init testedtested.call1(); // may throw a WantedException
      // call to be actually testedtested.call2(); // the call that is supposed to raise an exception}
  3. The ExpectedException rule is also an attempt to fix the previous caveats, but it feels a bit awkward to use as it uses an expectation style, EasyMock users know very well this style. It might be convenient for some, but if you follow Behaviour Driven Development (BDD) or Arrange Act Assert (AAA) principles the ExpectedException rule won't fit in those writing style. Aside from that it may suffer from the same issue as the @Test way, depending on where you place the expectation.

    @Rule ExpectedException thrown = ExpectedException.none()
    @Testpublic void call2_should_throw_a_WantedException__not_call1() {// expectationsthrown.expect(WantedException.class);thrown.expectMessage("boom");
    // init testedtested.call1(); // may throw a WantedException
    // call to be actually testedtested.call2(); // the call that is supposed to raise an exception}

    即使预期的异常放在测试语句之前,如果测试遵循BDD或AAA,它也会中断您的阅读流程。

    此外,请参阅JUnit上的这个评论问题,ExpectedException.JUnit 4.13-beta-2的作者甚至反对这种机制:

    拉取请求#1519:弃用预期的异常

    Assert.assert方法为验证异常提供了一种更好的方法。此外,当与其他规则(如TestWatcher)一起使用时,使用ExectedException容易出错,因为在这种情况下规则的顺序很重要。

因此,上述这些选项都有其所有的警告,显然不能免受编码器错误的影响。

  1. 在创建这个答案后,我意识到有一个项目看起来很有希望,它是捕获异常

    正如项目描述所说,它让编码人员编写流畅的代码行来捕获异常并为后一个断言提供此异常。您可以使用任何断言库,如HamcrestAssertJ

    取自主页的一个快速示例:

    // given: an empty listList myList = new ArrayList();
    // when: we try to get the first element of the listwhen(myList).get(1);
    // then: we expect an IndexOutOfBoundsExceptionthen(caughtException()).isInstanceOf(IndexOutOfBoundsException.class).hasMessage("Index: 1, Size: 0").hasNoCause();

    正如您所看到的代码非常简单,您在特定行上捕获异常,then API是将使用AssertJ API的别名(类似于使用assertThat(ex).hasNoCause()...)。在某种程度上,该项目依赖于FEST-断言AssertJ的祖先.编辑:似乎该项目正在酝酿Java8 Lambdas支持。

    目前,这个库有两个缺点:

    • 在写这篇文章的时候,值得注意的是,这个库是基于Mockito 1. x的,因为它在幕后创建了一个被测试对象的模拟。由于Mockito仍然没有更新,这个库不能与最终类或最终方法一起使用。即使它在当前版本中基于Mockito 2,这也需要声明一个全局模拟制造商(inline-mock-maker),这可能不是你想要的,因为这个模拟制造商与普通模拟制造商有不同的缺点。

    • 它还需要另一个测试依赖项。

    一旦库支持lambda,这些问题将不适用。但是,AssertJ工具集将复制该功能。

    考虑到所有因素,如果您不想使用catch-异常工具,我将推荐#0-#1块的旧好方法,至少在JDK7之前。对于JDK 8用户,您可能更喜欢使用AssertJ,因为它提供的不仅仅是断言异常。

  2. 使用JDK8,lambdas进入测试场景,它们已被证明是断言异常行为的一种有趣方式。AssertJ已更新以提供一个很好的流畅API来断言异常行为。

    和一个带有AssertJ的样本测试:

    @Testpublic void test_exception_approach_1() {...assertThatExceptionOfType(IOException.class).isThrownBy(() -> someBadIOOperation()).withMessage("boom!");}
    @Testpublic void test_exception_approach_2() {...assertThatThrownBy(() -> someBadIOOperation()).isInstanceOf(Exception.class).hasMessageContaining("boom");}
    @Testpublic void test_exception_approach_3() {...// whenThrowable thrown = catchThrowable(() -> someBadIOOperation());
    // thenassertThat(thrown).isInstanceOf(Exception.class).hasMessageContaining("boom");}
  3. With a near-complete rewrite of JUnit 5, assertions have been improved a bit, they may prove interesting as an out of the box way to assert properly exception. But really the assertion API is still a bit poor, there's nothing outside assertThrows.

    @Test@DisplayName("throws EmptyStackException when peeked")void throwsExceptionWhenPeeked() {Throwable t = assertThrows(EmptyStackException.class, () -> stack.peek());
    Assertions.assertEquals("...", t.getMessage());}

    正如您所注意到的,assertEquals仍然返回void,因此不允许像AssertJ这样的链接断言。

    此外,如果您记得名称与MatcherAssert发生冲突,请准备好与Assertions发生相同的冲突。

我想得出结论,今天(2017-03-03)AssertJ的易用性,可发现的API,快速的开发速度以及作为事实上测试依赖项是JDK8的最佳解决方案,无论测试框架(JUnit与否),以前的JDK应该依赖#0-#1块,即使它们感觉笨重。

这个答案是从复制的另一个问题没有相同的可见性,我是同一个作者。

在JUnit 4或更高版本中,您可以测试异常,如下所示

@Rulepublic ExpectedException exceptions = ExpectedException.none();


这提供了许多可用于改进我们的JUnit测试的功能。
如果您看到下面的示例,我将在异常上测试3件事。

  1. 抛出的异常类型
  2. 异常消息
  3. 例外的原因


public class MyTest {
@Rulepublic ExpectedException exceptions = ExpectedException.none();
ClassUnderTest classUnderTest;
@Beforepublic void setUp() throws Exception {classUnderTest = new ClassUnderTest();}
@Testpublic 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;
@Testvoid 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");}

使用trycatch

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

测试ExpectedException规则。

@Rulepublic ExpectedException thrown = ExpectedException.none();
@Testpublic void testReadFile() throws FileNotFoundException {    
thrown.expect(FileNotFoundException.class);thrown.expectMessage(startsWith("The file test.txt"));myClass.readFile("test.txt");}

您可以在用于异常测试的JUnit4 wikibad.robot-期望异常JUnit规则中阅读有关异常测试的更多信息。

使用Java8,您可以创建一个方法,该方法使用代码进行检查并将预期异常作为参数:

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已经发布,最好的选择是使用Assertions.assertThrows()(用于JUnit 5)和Assert.assertThrows()(用于JUnit 4.13)。见JUnit 5用户指南.

这是一个验证抛出异常的示例,并使用真相对异常消息进行断言:

public class FooTest {@Testpublic void doStuffThrowsIndexOutOfBoundsException() {Foo foo = new Foo();
IndexOutOfBoundsException e = assertThrows(IndexOutOfBoundsException.class, foo::doStuff);
assertThat(e).hasMessageThat().contains("woops!");}}

与其他答案中的方法相比,优点是:

  1. 内置到JUnit中
  2. 如果lambda中的代码没有抛出异常,则会得到一个有用的异常消息,如果抛出不同的异常,则会得到一个堆栈跟踪
  3. 简洁
  4. 允许您的测试遵循Arrange-Act-Aste
  5. 您可以准确地指出您希望抛出异常的代码
  6. 您不需要在throws子句中列出预期的异常
  7. 您可以使用您选择的断言框架对捕获的异常进行断言

我的解决方案使用Java8 lambda:

public static <T extends Throwable> T assertThrows(Class<T> expected, ThrowingRunnable action) throws Throwable {try {action.run();Assert.fail("Did not throw expected " + expected.getSimpleName());return null; // never actually} catch (Throwable actual) {if (!expected.isAssignableFrom(actual.getClass())) { // runtime '!(actual instanceof expected)'System.err.println("Threw " + actual.getClass().getSimpleName()+ ", which is not a subtype of expected "+ expected.getSimpleName());throw actual; // throw the unexpected Throwable for maximum transparency} else {return (T) actual; // return the expected Throwable for further examination}}}

您必须定义一个FunctionalInterface,因为Runnable没有声明所需的throws

@FunctionalInterfacepublic interface ThrowingRunnable {void run() throws Throwable;}

该方法可以使用如下:

class CustomException extends Exception {public final String message;public CustomException(final String message) { this.message = message;}}CustomException e = assertThrows(CustomException.class, () -> {throw new CustomException("Lorem Ipsum");});assertEquals("Lorem Ipsum", e.message);

有两种编写测试用例的方法

  1. 用方法抛出的异常注释测试。类似这样的@Test(expected = IndexOutOfBoundsException.class)
  2. 您可以简单地使用try cat块捕获测试类中的异常,并对从测试类中的方法抛出的消息断言。

    try{}catch(exception to be thrown from method e){assertEquals("message", e.getmessage());}

I hope this answers your queryHappy learning...

我在mkong博客中找到了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 {
@Rulepublic ExpectedException thrown = ExpectedException.none();
@Testpublic void testNameNotFoundException() throws NameNotFoundException {
//test specific type of exceptionthrown.expect(NameNotFoundException.class);
//test messagethrown.expectMessage(is("Name is empty!"));
//test detailthrown.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表达式中使用final对象引用。此解决方案允许继续测试断言,而不是期望使用@Test(expected = IndexOutOfBoundsException.class)解决方案在方法级别恢复。

我推荐库assertj-core来处理jUnit测试中的异常

在java 8中,像这样:

//given
//whenThrowable throwable = catchThrowable(() -> anyService.anyMethod(object));
//thenAnyException anyException = (AnyException) throwable;assertThat(anyException.getMessage()).isEqualTo("........");assertThat(exception.getCode()).isEqualTo(".......);
try {my method();fail( "This method must thrwo" );} catch (Exception ex) {assertThat(ex.getMessage()).isEqual(myErrormsg);}
    @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框架有#0方法:

ArithmeticException exception = assertThrows(ArithmeticException.class, () ->calculator.divide(1, 0));assertEquals("/ by zero", exception.getMessage());
  • 对于JUnit 5,它在#0类;
  • 对于JUnit 4.13,它属于#0类;
  • 对于早期版本的JUnit 4:只需将#0上的引用添加到您的项目中,您就可以从JUnit 5获得运行良好的版本。