代码之家  ›  专栏  ›  技术社区  ›  SCdF

如何断言在JUnit4测试中抛出了某个异常?

  •  1765
  • SCdF  · 技术社区  · 16 年前

    如何使用JUnit4来测试某些代码引发异常?

    我当然可以这样做:

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

    我记得有注释或assert.xyz或 某物 在这种情况下,这不是那么笨拙,更符合朱尼特的精神。

    32 回复  |  直到 6 年前
        1
  •  2123
  •   Pang Ajmal PraveeN    6 年前

    Junit 4对此提供了支持:

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

    参考文献: https://junit.org/junit4/faq.html#atests_7

        2
  •  1221
  •   NamshubWriter    7 年前

    编辑 既然Junit5已经发布了,最好的选择是使用 Assertions.assertThrows() (见 my other answer )

    如果您没有迁移到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()

    this article 详情

        3
  •  431
  •   daveb    16 年前

    小心使用预期的异常,因为它只声明 方法 抛出了那个异常,而不是 特定代码行 在测试中。

    我倾向于将其用于测试参数验证,因为此类方法通常非常简单,但更复杂的测试可能更好地用于:

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

    运用判断。

        4
  •  197
  •   xehpuk    8 年前

    正如前面所回答的,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();
    }
    

    断言引发接受一个函数接口,该接口的实例可以用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

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

        5
  •  95
  •   walsh    6 年前

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

    • 对于JUnit4.x,请使用测试注释的可选“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();
          }
      }
      
    • 您还可以使用JUnit3框架下广泛使用的经典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.
          }
      }
      
    • 最后,对于junit5.x,您还可以使用assertthrow,如下所示

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

      • 当只想测试异常类型时,使用第1种方法
      • 当您希望进一步测试异常消息时,使用其他三种方法
      • 如果您使用JUnit 3,则首选第3个
      • 如果你喜欢Junit 5,那么你应该喜欢第四个
    • 更多信息,您可以阅读 this document junit5 user guide 详情。

        6
  •  71
  •   bric3    6 年前

    DR

    • JDK8之前:我会推荐旧的 try - catch 块。( 不要忘记添加 fail() 抓住 )

    • JDK8之后:使用断言j或自定义lambda断言 例外 行为。

    无论是6月4日还是6月5日。

    长篇小说

    你可以给自己写一封 自己动手 尝试 - 抓住 阻止或使用JUnit工具( @Test(expected = ...) @Rule ExpectedException JUnit规则功能)。

    但是这种方法不太优雅,也不太好混合 可读性方面 使用其他工具。

    1. 这个 尝试 - 抓住 块您必须围绕测试的行为编写块,并在catch块中编写断言,这可能很好,但许多人发现这种风格会中断测试的读取流。你还需要写一个 Assert.fail 尝试 阻止,否则测试可能会错过断言的一侧; 偏振模色散 , 芬德布斯 声纳 会发现这些问题。

    2. 这个 @测试(应为=…) 这个特性很有趣,因为您可以编写更少的代码,然后编写这个测试就不太容易出现编码错误。 但是 这种方法缺乏一些方面。

      • 如果测试需要检查异常的其他内容,如原因或消息(好的异常消息非常重要,精确的异常类型可能不够)。
      • 另外,当期望值被放置在方法中时,根据测试代码的编写方式,测试代码的错误部分可能引发异常,导致错误的阳性测试,我不确定 偏振模色散 , 芬德布斯 声纳 将给出此类代码的提示。

        @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
        }
        
    3. 这个 ExpectedException 规则也试图修正之前的警告,但是使用预期样式时会感到有点尴尬, 易思莫克 用户非常了解这种风格。对一些人来说可能很方便,但是如果你跟着 行为驱动的发展 (BDD)或 排列动作断言 (aaa)原则 预期感受 规则不适合那些写作风格。除此之外,它可能与 @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,它也会中断您的读取流。

      也看到这个 comment 作者朱尼特问题 预期感受 . JUnit 4.13-beta-2 甚至反对这种机制:

      Pull request #1519 :不预测预期异常

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

    因此,以上这些选项都有它们所有的警告,而且显然不能免疫编码错误。

    1. 我在创建这个答案后意识到一个项目看起来很有希望, catch-exception .

      正如项目描述所说,它让编码人员用一行流畅的代码编写捕获异常的代码,并为以后的断言提供这个异常。你可以使用任何断言库,比如 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();
      

      正如您所看到的,代码非常简单,您可以在特定的行上捕获异常,即 then API是一个将使用断言API的别名(类似于使用 assertThat(ex).hasNoCause()... ) 在某种程度上,该项目依赖于fest assert,即assetj的祖先。 . 编辑: 看起来这个项目正在酝酿一个Java 8的LAMBDAS支持。

      目前,该图书馆存在两个缺点:

      • 在撰写本文的时候,值得注意的是,这个库是基于mockito 1.x的,因为它在场景后面创建了一个被测试对象的模拟。因为mockito还没有更新 此库无法使用最终类或最终方法 . 即使它是基于当前版本的mockito 2,这也需要声明一个全球的mock maker( inline-mock-maker ,这可能不是你想要的,因为这个mockmaker有不同于常规mockmaker的缺点。

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

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

      考虑到所有因素,如果您不想使用catch异常工具,我将推荐 尝试 - 抓住 块,至少到JDK7。对于JDK8用户,您可能更喜欢使用断言j,因为它提供的断言可能不仅仅是断言异常。

    2. 有了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");
      }
      
    3. 随着JUnit5的几乎完全重写,断言已经 improved 有一点,作为一种现成的方法来断言正确的异常,它们可能会很有趣。但实际上断言API还是有点差,外面什么都没有 assertThrows .

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

      正如你注意到的 assertEquals 仍在返回 void 因此,不允许链接断言(如断言j)。

      如果你记得名字与 Matcher Assert 准备好迎接同样的冲突 Assertions .

    我想总结一下,今天(2017-03-03) 断言J 易用性、可发现的API、快速的开发速度以及 事实上的 测试依赖性是JDK8的最佳解决方案,不管测试框架(JUnit与否),以前的JDK应该依赖于 尝试 - 抓住 即使感觉笨重,也要用木块。

    此答案已从复制 another question 没有相同的可见性,我是同一个作者。

        7
  •  40
  •   NamshubWriter    7 年前

    既然Junit 5已经发布了,最好的选择是使用 Assertions.assertThrows() (见 这个 Junit 5 User Guide )

    下面是一个验证抛出异常并使用 Truth 要对异常消息进行断言,请执行以下操作:

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

    与其他答案中的方法相比,优势在于:

    1. 建在朱尼特
    2. 如果lambda中的代码不引发异常,则会收到一条有用的异常消息;如果stacktrace引发不同的异常,则会收到一条stacktrace消息。
    3. 简洁的
    4. 允许测试遵循排列动作断言
    5. 您可以精确地指示您希望抛出异常的代码
    6. 您不需要在 throws 条款
    7. 您可以使用所选的断言框架对捕获的异常进行断言。

    类似的方法将添加到 org.junit Assert 在JUnit 4.13。

        8
  •  37
  •   Dawood ibn Kareem    10 年前

    这个怎么样:捕获一个非常普通的异常,确保它不在catch块中,然后断言该异常的类是您期望的。如果a)异常类型错误(例如,如果改为使用空指针),以及b)从未引发异常,则此断言将失败。

    public void testFooThrowsIndexOutOfBoundsException() {
      Throwable e = null;
    
      try {
        foo.doStuff();
      } catch (Throwable ex) {
        e = ex;
      }
    
      assertTrue(e instanceof IndexOutOfBoundsException);
    }
    
        9
  •  31
  •   weston    8 年前

    使用一个 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");
    

    Maven/Gradle instructions here.

        10
  •  30
  •   rwitzel    13 年前

    为了解决同样的问题,我设立了一个小项目: http://code.google.com/p/catch-exception/

    用这个小助手你会写

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

    这比JUnit 4.7的ExpectedException规则更详细。 与skaffman提供的解决方案相比,您可以指定期望异常出现在哪一行代码中。我希望这有帮助。

        11
  •  30
  •   MariuszS    10 年前

    BDD 风格解决方案: JUnit 4 + Catch Exception + AssertJ

    @Test
    public void testFooThrowsIndexOutOfBoundsException() {
    
        when(foo).doStuff();
    
        then(caughtException()).isInstanceOf(IndexOutOfBoundsException.class);
    
    }
    

    源代码

    依赖关系

    eu.codearte.catch-exception:catch-exception:1.3.3
    
        12
  •  24
  •   Maximilian Peters    7 年前

    更新: JUnit5改进了异常测试: assertThrows .

    以下示例来自: Junit 5 User Guide

     @Test
    void exceptionTesting() {
        Throwable exception = assertThrows(IllegalArgumentException.class, () -> 
        {
            throw new IllegalArgumentException("a message");
        });
        assertEquals("a message", exception.getMessage());
    }
    

    使用JUnit 4的原始答案。

    有几种方法可以测试是否引发了异常。我在我的帖子中也讨论了以下选项 How to write great unit tests with 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!"));
        }
    
    }
    

    测试用 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 for Exception testing bad.robot - Expecting Exceptions JUnit Rule .

        13
  •  20
  •   Dawood ibn Kareem    10 年前

    您也可以这样做:

    @Test
    public void testFooThrowsIndexOutOfBoundsException() {
        try {
            foo.doStuff();
            assert false;
        } catch (IndexOutOfBoundsException e) {
            assert true;
        }
    }
    
        14
  •  12
  •   Gerold Broser    7 年前

    imho,在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"); 可能更好。

        15
  •  11
  •   Daniel Käfer    8 年前

    Junit 5解决方案

    @Test
    void testFooThrowsIndexOutOfBoundsException() {    
      Throwable exception = expectThrows( IndexOutOfBoundsException.class, foo::doStuff );
    
      assertEquals( "some message", exception.getMessage() );
    }
    

    关于Junit 5的更多信息 http://junit.org/junit5/docs/current/user-guide/#writing-tests-assertions

        16
  •  10
  •   Hugh Perkins    12 年前

    我在这里尝试了许多方法,但它们要么很复杂,要么不完全符合我的要求。实际上,可以非常简单地编写一个助手方法:

    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;并且可以与最终类一起工作。

        17
  •  8
  •   Mark Bessey    16 年前

    JUnit对此有内置支持, "expected" attribute

        18
  •  8
  •   Mike Nakis    7 年前

    Java 8解决方案

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

    • 利用Java 8 LAMBDAS
    • 依靠任何魔法
    • 允许您检查单个测试方法中的多个异常
    • 检查测试方法中的特定行集是否引发异常,而不是整个测试方法中的任何未知行。
    • 生成引发的实际异常对象,以便进一步检查它

    我写了一个实用函数:

    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 "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.
    }
    

    ( taken from my blog )

    使用方法如下:

    @Test
    public void testThrows()
    {
        RuntimeException e = expectException( RuntimeException.class, () -> 
            {
                throw new RuntimeException( "fail!" );
            } );
        assert e.getMessage().equals( "fail!" );
    }
    
        19
  •  8
  •   Dherik    6 年前

    最灵活和优雅的答案是我在 Mkyong blog . 它具有 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("");
    
        }
    
    }
    
        20
  •  7
  •   Macchiatow    11 年前

    在我的例子中,我总是从数据库中得到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));
    }
    
        21
  •  5
  •   evandrix    8 年前

    只需制作一个可以关闭和打开的匹配器,如下所示:

    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();
    
        22
  •  5
  •   J-J    8 年前

    在JUnit4或更高版本中,您可以按以下方式测试异常

    @Rule
    public ExpectedException exceptions = ExpectedException.none();
    


    这提供了许多可以用来改进JUnit测试的特性。
    如果您看到下面的示例,我将对异常进行3项测试。

    1. 引发的异常类型
    2. 异常消息
    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");
        }
    
    }
    
        23
  •  5
  •   Shessuky    7 年前

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

    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());
    }
    
        24
  •  4
  •   Community CDub    7 年前

    除了什么 NamShubWriter 已经说过,确保:

    • ExpectedException实例是 公众的 ( Related Question )
    • 预期感受 不是 在say中实例化了@before方法。这个 post 清楚地解释了朱尼特执行命令的所有错综复杂之处。

    这样做:

    @Rule    
    public ExpectedException expectedException;
    
    @Before
    public void setup()
    {
        expectedException = ExpectedException.none();
    }
    

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

        25
  •  1
  •   Shirsh Sinha    8 年前

    例如,您想要为下面提到的代码片段编写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"});
    }
    
        26
  •  1
  •   Piotr Rogowski    6 年前

    我建议图书馆 assertj-core 在JUnit测试中处理异常

    在Java 8中,像这样:

    //given
    
    //when
    Throwable throwable = catchThrowable(() -> anyService.anyMethod(object));
    
    //then
    AnyException anyException = (AnyException) throwable;
    assertThat(anyException.getMessage()).isEqualTo("........");
    assertThat(exception.getCode()).isEqualTo(".......);
    
        27
  •  0
  •   fahrenx    7 年前

    使用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);
    

    效益:

    • 不依赖任何图书馆
    • 局部检查-更精确,如果需要,允许在一个测试中有多个这样的断言
    • 易于使用
        28
  •  0
  •   heio    7 年前

    我的解决方案使用Java 8 lambdas:

    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
            }
        }
    }
    

    您必须定义一个功能接口,因为 Runnable 不声明必需的 throws .

    @FunctionalInterface
    public 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);
    
        29
  •  0
  •   Sandeep Sukhija    7 年前

    编写测试用例有两种方法

    1. 用方法抛出的异常来注释测试。像这样的东西 @Test(expected = IndexOutOfBoundsException.class)
    2. 您可以使用try catch块在测试类中捕获异常,并对从测试类中的方法抛出的消息进行断言。

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

    我希望这能回答你的问题 快乐学习…

        30
  •  0
  •   Donatello    6 年前

    带有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));
    

    请注意,唯一的限制是使用 final lambda表达式中的对象引用。 此解决方案允许继续测试断言,而不是在方法级别使用 @Test(expected = IndexOutOfBoundsException.class) 解决方案。