csdnceshi57
perhaps?
2008-10-01 06:56
采纳率: 100%
浏览 2.7k
已采纳

如何在 junit4测试中抛出某个异常?

该如何使用 JUnit4来测试某些代码抛出的异常?

我当然可以这样做:

@Test
public void testFooThrowsIndexOutOfBoundsException() {
  boolean thrown = false;

  try {
    foo.doStuff();
  } catch (IndexOutOfBoundsException e) {
    thrown = true;
  }

  assertTrue(thrown);
}

我记得有一个注释或者 Assert.xyz 之类的东西,对于这类情况来说,它远没有那么复杂,而是更符合 JUnit 的精神。

转载于:https://stackoverflow.com/questions/156503/how-do-you-assert-that-a-certain-exception-is-thrown-in-junit-4-tests

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 邀请回答

30条回答 默认 最新

  • weixin_41568183
    零零乙 2008-10-01 07:12
    已采纳

    JUnit 4 has support for this:

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

    Reference: https://junit.org/junit4/faq.html#atests_7

    点赞 评论
  • csdnceshi54
    hurriedly% 2008-10-01 07:03

    How about this: Catch a very general exception, make sure it makes it out of the catch block, then assert that the class of the exception is what you expect it to be. This assert will fail if a) the exception is of the wrong type (eg. if you got a Null Pointer instead) and b) the exception wasn't ever thrown.

    public void testFooThrowsIndexOutOfBoundsException() {
      Throwable e = null;
    
      try {
        foo.doStuff();
      } catch (Throwable ex) {
        e = ex;
      }
    
      assertTrue(e instanceof IndexOutOfBoundsException);
    }
    
    点赞 评论
  • csdnceshi55
    ~Onlooker 2008-10-01 07:05

    JUnit has built-in support for this, with an "expected" attribute

    点赞 评论
  • weixin_41568110
    七度&光 2008-10-01 09:31

    Be careful using expected exception, because it only asserts that the method threw that exception, not a particular line of code in the test.

    I tend to use this for testing parameter validation, because such methods are usually very simple, but more complex tests might better be served with:

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

    Apply judgement.

    点赞 评论
  • csdnceshi58
    Didn"t forge 2010-05-29 17:16

    Edit Now that JUnit5 has released, the best option would be to use Assertions.assertThrows() (see my other answer).

    If you haven't migrated to JUnit 5, but can use JUnit 4.7, you can use the ExpectedException Rule:

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

    This is much better than @Test(expected=IndexOutOfBoundsException.class) because the test will fail if IndexOutOfBoundsException is thrown before foo.doStuff()

    See this article for details

    点赞 评论
  • csdnceshi67
    bug^君 2011-10-28 09:26

    To solve the same problem I did set up a small project: http://code.google.com/p/catch-exception/

    Using this little helper you would write

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

    This is less verbose than the ExpectedException rule of JUnit 4.7. In comparison to the solution provided by skaffman, you can specify in which line of code you expect the exception. I hope this helps.

    点赞 评论
  • csdnceshi71
    Memor.の 2012-10-10 15:02

    I tried many of the methods here, but they were either complicated or didn't quite meet my requirements. In fact, one can write a helper method quite simply:

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

    Use it like this:

    assertException(new BlastContainer() {
        @Override
        public void test() throws Exception {
            doSomethingThatShouldExceptHere();
        }
    });
    

    Zero dependencies: no need for mockito, no need powermock; and works just fine with final classes.

    点赞 评论
  • csdnceshi58
    Didn"t forge 2013-05-07 17:17

    You can also do this:

    @Test
    public void testFooThrowsIndexOutOfBoundsException() {
        try {
            foo.doStuff();
            assert false;
        } catch (IndexOutOfBoundsException e) {
            assert true;
        }
    }
    
    点赞 评论
  • weixin_41568183
    零零乙 2013-06-05 20:12

    Just make a Matcher that can be turned off and on, like this:

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

    To use it:

    add public ExpectedException exception = ExpectedException.none();, then:

    ExceptionMatcher exMatch = new ExceptionMatcher(MyException.class);
    exception.expect(exMatch);
    someObject.somethingThatThrowsMyException();
    exMatch.off();
    
    点赞 评论
  • csdnceshi76
    斗士狗 2013-07-02 09:03

    In my case I always get RuntimeException from db, but messages differ. And exception need to be handled respectively. Here is how I tested it:

    @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));
    }
    
    点赞 评论
  • csdnceshi52
    妄徒之命 2013-11-15 19:17

    BDD Style Solution: JUnit 4 + Catch Exception + AssertJ

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

    Source code

    Dependencies

    eu.codearte.catch-exception:catch-exception:1.3.3
    
    点赞 评论
  • csdnceshi54
    hurriedly% 2014-07-07 22:35

    As answered before, there are many ways of dealing with exceptions in JUnit. But with Java 8 there is another one: using Lambda Expressions. With Lambda Expressions we can achieve a syntax like this:

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

    assertThrown accepts a functional interface, whose instances can be created with lambda expressions, method references, or constructor references. assertThrown accepting that interface will expect and be ready to handle an exception.

    This is relatively simple yet powerful technique.

    Have a look at this blog post describing this technique: http://blog.codeleak.pl/2014/07/junit-testing-exception-with-java-8-and-lambda-expressions.html

    The source code can be found here: https://github.com/kolorobot/unit-testing-demo/tree/master/src/test/java/com/github/kolorobot/exceptions/java8

    Disclosure: I am the author of the blog and the project.

    点赞 评论
  • csdnceshi75
    衫裤跑路 2015-03-09 11:21

    We can use an assertion fail after the method that must return an exception:

    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());
    }
    
    点赞 评论
  • csdnceshi69
    YaoRaoLov 2015-03-10 21:49

    IMHO, the best way to check for exceptions in JUnit is the try/catch/fail/assert pattern:

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

    The assertTrue might be a bit strong for some people, so assertThat(e.getMessage(), containsString("the message"); might be preferable.

    点赞 评论
  • csdnceshi59
    ℙℕℤℝ 2015-05-22 19:09

    Additionally to what NamShubWriter has said, make sure that:

    • The ExpectedException instance is public (Related Question)
    • The ExpectedException isn't instantiated in say, the @Before method. This post clearly explains all the intricacies of JUnit's order of execution.

    Do not do this:

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

    Finally, this blog post clearly illustrates how to assert that a certain exception is thrown.

    点赞 评论
  • csdnceshi60
    ℡Wang Yan 2015-08-05 08:05

    in junit, there are four ways to test exception.

    • 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 {
          @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();
          }
      }
      
    • you also can use the classic try/catch way widely used under junit 3 framework

      @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.
          }
      }
      
    • finally, for junit5.x, you can also use assertThrows as following

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

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

    点赞 评论
  • weixin_41568110
    七度&光 2015-12-18 18:52

    Java 8 solution

    If you would like a solution which:

    • Utilizes Java 8 lambdas
    • Does not depend on any JUnit magic
    • Allows you to check for multiple exceptions within a single test method
    • Checks for an exception being thrown by a specific set of lines within your test method instead of any unknown line in the entire test method
    • Yields the actual exception object that was thrown so that you can further examine it

    Here is a utility function that I wrote:

    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)

    Use it as follows:

    @Test
    public void testThrows()
    {
        RuntimeException e = expectException( RuntimeException.class, () -> 
            {
                throw new RuntimeException( "fail!" );
            } );
        assert e.getMessage().equals( "fail!" );
    }
    
    点赞 评论
  • weixin_41568196
    撒拉嘿哟木头 2016-03-05 11:07

    Using an AssertJ assertion, which can be used alongside JUnit:

    import static org.assertj.core.api.Assertions.*;
    
    @Test
    public void testFooThrowsIndexOutOfBoundsException() {
      Foo foo = new Foo();
    
      assertThatThrownBy(() -> foo.doStuff())
            .isInstanceOf(IndexOutOfBoundsException.class);
    }
    

    It's better than @Test(expected=IndexOutOfBoundsException.class) because it guarantees the expected line in the test threw the exception and lets you check more details about the exception, such as message, easier:

    assertThatThrownBy(() ->
           {
             throw new Exception("boom!");
           })
        .isInstanceOf(Exception.class)
        .hasMessageContaining("boom");
    

    Maven/Gradle instructions here.

    点赞 评论
  • weixin_41568183
    零零乙 2016-07-24 15:00

    JUnit 5 Solution

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

    More Infos about JUnit 5 on http://junit.org/junit5/docs/current/user-guide/#writing-tests-assertions

    点赞 评论
  • csdnceshi61
    derek5. 2016-10-29 07:34

    Take for example, you want to write Junit for below mentioned code fragment

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

    The above code is to test for some unknown exception that may occur and the below one is to assert some exception with custom message.

     @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"});
    }
    
    点赞 评论
  • csdnceshi54
    hurriedly% 2016-12-07 14:19

    tl;dr

    • pre-JDK8 : I will recommend the old good try-catch block.

    • post-JDK8 : Use AssertJ or custom lambdas to assert exceptional behaviour.

    Regardless of Junit 4 or JUnit 5.

    the long story

    It is possible to write yourself a do it yourself try-catch block or use the JUnit tools (@Test(expected = ...) or the @Rule ExpectedException JUnit rule feature).

    But these way are not so elegant and don't mix well readability wise with other tools.

    1. The try-catch block you have to write the block around the tested behavior, and write the assertion in the catch block, that may be fine but many find taht this style interrupts the reading flow of a test. Also you need to write an Assert.fail at the end of the try block otherwise the test may miss one side of the assertions ; PMD, findbugs or Sonar will spot such issues.

    2. The @Test(expected = ...) feature is interesting as you can write less code and then writing this test is supposedly less prone to coding errors. But ths approach is lacking a some areas.

      • If the test needs to check additional things on the exception like the cause or the message (good exception messages are really important, having a precise exception type may not be enough).
      • Also as the expectation is placed around in the method, depending on how the tested code is written then the wrong part of the test code can throw the exception, leading to false positive test and I m not sure that PMD, findbugs or Sonar will give hints on such code.

        @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. 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 knows 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 of that it may suffer from the same issue as the as the @Test way, depending where you place the expectation.

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

      Even the expected exception is placed before the test statement, it breaks your reading flow if the tests follow BDD or AAA.

      Also see this comment issue on JUnit of the author of ExpectedException.

    So these above options have all their load of caveats, and clearly not immune to coder errors.

    1. There's a project I became aware after creating this answer that looks promising, it's catch-exception.

      As the description of the project says, it let a coder write in a fluent line of code catching the exception and offer this exception for later assertion. And you can use any assertion library like Hamcrest or AssertJ.

      A rapid example taken from the home page :

      // 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();
      

      As you can see the code is really straightforward, you catch the exception on a specific line, the then API is an alias that will use AssertJ APIs (similar to using assertThat(ex).hasNoCause()...). At some point the project relied on FEST-Assert the ancestor of AssertJ. EDIT: It seems the project is brewing a Java 8 Lambdas support.

      Currently this library has two shortcomings :

      • At the time of this writing it is noteworthy to say this library is based on Mockito 1.x as it creates a mock of the tested object behind the scene. As Mockito is still not updated this library cannot work with final classes or final methods. And even if it was based on mockito 2 in the current version, this would require to declare a global mock maker (inline-mock-maker), something that may not what you want, as this mockmaker has different drawbacks that the regular mockmaker.

      • It requires yet another test dependency.

      These issues won't apply once the library will support lambdas, however the functionality will be duplicated by AssertJ toolset.

      Taking all into account if you don't want to use the catch-exception tool, I will recommend the old good way of the try-catch block, at least up to the JDK7. And for JDK 8 users you might prefer to use AssertJ as it offers may more than just asserting exceptions.

    2. With the JDK8, lambdas enter the test scene, and they have proved to be an interesting way to assert exceptional behaviour. AssertJ has been updated to provide a nice fluent API to assert exceptional behaviour.

      And a sample test with 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. 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());
      }
      

      As you noticed assertEquals is still returning void, and as such doesn't allow chaining assertions like AssertJ.

      Also if you remember name clash with Matcher or Assert, be prepared to meet the same clash with Assertions.

    I'd like to conclude that today (2017-03-03) AssertJ's ease of use, discoverable API, rapid pace of development and as a de facto test dependency is the best solution with JDK8 regardless of the test framework (JUnit or not), prior JDKs should instead rely on try-catch blocks even if they feel clunky.

    This answer has been copied from another question that don't have the same visibility, I am the same author.

    点赞 评论
  • csdnceshi51
    旧行李 2016-12-08 05:48

    In JUnit 4 or later you can test the exceptions as follows

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


    this provides a lot of features which can be used to improve our JUnit tests.
    If you see the below example I am testing 3 things on the exception.

    1. The Type of exception thrown
    2. The exception Message
    3. The cause of the exception


    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");
        }
    
    }
    
    点赞 评论
  • csdnceshi76
    斗士狗 2017-01-10 01:29

    Update: JUnit5 has an improvement for exceptions testing: assertThrows.

    following example is from: Junit 5 User Guide

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

    Original answer using JUnit 4.

    There are several ways to test that an exception is thrown. I have also discussed the below options in my post How to write great unit tests with JUnit

    Set the expected parameter @Test(expected = FileNotFoundException.class).

    @Test(expected = FileNotFoundException.class) 
    public void testReadFile() { 
        myClass.readFile("test.txt");
    }
    

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

    Testing with ExpectedException Rule.

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

    You could read more about exceptions testing in JUnit4 wiki for Exception testing and bad.robot - Expecting Exceptions JUnit Rule.

    点赞 评论
  • csdnceshi51
    旧行李 2017-10-01 12:03

    With Java 8 you can create a method taking a code to check and expected exception as parameters:

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

    and then inside your test:

    expectException(() -> list.sublist(0, 2).get(2), IndexOutOfBoundsException.class);
    

    Benefits:

    • not relying on any library
    • localised check - more precise and allows to have multiple assertions like this within one test if needed
    • easy to use
    点赞 评论
  • csdnceshi60
    ℡Wang Yan 2017-10-01 16:42

    Now that JUnit 5 has released, the best option is to use Assertions.assertThrows() (see the Junit 5 User Guide).

    Here is an example that verifies an exception is thrown, and uses Truth to make assertions on the exception message:

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

    The advantages over the approaches in the other answers are:

    1. Built into JUnit
    2. You get a useful exception message if the code in the lambda doesn't throw an exception, and a stacktrace if it throws a different exception
    3. Concise
    4. Allows your tests to follow Arrange-Act-Assert
    5. You can precisely indicate what code you are expecting to throw the exception
    6. You don't need to list the expected exception in the throws clause
    7. You can use the assertion framework of your choice to make assertions about the caught exception

    A similar method will be added to org.junit Assert in JUnit 4.13.

    点赞 评论
  • csdnceshi53
    Lotus@ 2017-10-04 11:06

    My solution using 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
            }
        }
    }
    

    You have to define a FunctionalInterface, because Runnable doesn't declare the required throws.

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

    The method can be used as follows:

    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);
    
    点赞 评论
  • weixin_41568196
    撒拉嘿哟木头 2017-11-09 06:23

    There are two ways of writing test case

    1. Annotate the test with the exception which is thrown by the method. Something like this @Test(expected = IndexOutOfBoundsException.class)
    2. You can simply catch the exception in the test class using the try catch block and assert on the message that is thrown from the method in test class.

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

    I hope this answers your query Happy learning...

    点赞 评论
  • csdnceshi56
    lrony* 2018-01-25 11:10

    The most flexible and elegant answer for Junit 4 I found in the Mkyoung blog. It have the flexibility of the try/catch using the @Rule annotation. I liked this approach because I already needed to read specific attributes of a customized exception.

    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("");
    
        }
    
    }
    
    点赞 评论
  • weixin_41568183
    零零乙 2018-04-06 15:52

    Junit4 solution with Java8 is to use this function:

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

    Usage is then:

        assertThrows(ValidationException.class,
                () -> finalObject.checkSomething(null));
    

    Note that the only limitation is to use a final object reference in lambda expression. This solution allows to continue test assertions instead of expecting thowable at method level using @Test(expected = IndexOutOfBoundsException.class) solution.

    点赞 评论
  • csdnceshi58
    Didn"t forge 2018-07-18 11:32

    I recomend library assertj-core to handle exception in junit test

    In java 8, like this:

    //given
    
    //when
    Throwable throwable = catchThrowable(() -> anyService.anyMethod(object));
    
    //then
    AnyException anyException = (AnyException) throwable;
    assertThat(anyException.getMessage()).isEqualTo("........");
    assertThat(exception.getCode()).isEqualTo(".......);
    
    点赞 评论

相关推荐