Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mockito verify after exception Junit 4.10

I am testing a method with an expected exception. I also need to verify that some cleanup code was called (on a mocked object) after the exception is thrown, but it looks like that verification is being ignored. Here is the code. I am using the Junit ExpectedException Rule to verify the expected exception.

@Rule public ExpectedException expectedEx = ExpectedException.none();  @Test public void testExpectedException() {    MockedObject mockObj = mock(MockedObj.class);    MySubject subject = new MySubject(mockedObj);    expectedEx.expect(MyException.class);    expectedEx.expectMessage("My exception message.");    subject.someMethodThrowingException();    verify(mockObj).        someCleanup(eq(...)); } 

It seems like the verify is totally being ignored. No matter what method I put in the verify, my test is passing, which is not what I want.

Any idea why thats happenning?

like image 999
Eqbal Avatar asked Nov 05 '12 00:11

Eqbal


People also ask

How do you write test cases for exceptions in JUnit 4?

When using JUnit 4, we can simply use the expected attribute of the @Test annotation to declare that we expect an exception to be thrown anywhere in the annotated test method. In this example, we've declared that we're expecting our test code to result in a NullPointerException.

Should you use Mockito verify?

Mockito verify() method can be used to test number of method invocations too. We can test exact number of times, at least once, at least, at most number of invocation times for a mocked method. We can use verifyNoMoreInteractions() after all the verify() method calls to make sure everything is verified.


2 Answers

Once Exception is thrown in UT, all the code below that will be ignored.

@Test(expected = Exception.class) public void testExpectedException() {    MockedObject mockObj = mock(MockedObj.class);    MySubject subject = new MySubject(mockedObj);    subject.doSomething(); // If this line results in an exception then all the code below this will be ignored.    subject.someMethodThrowingException();    verify(mockObj).        someCleanup(eq(...)); } 

To counter this and verify all the calls made, we can use try with finally.

@Test(expected = Exception.class)     public void testExpectedException() {           MockedObject mockObj = mock(MockedObj.class);           MySubject subject = new MySubject(mockedObj);           try {                subject.someMethodThrowingException();            } finally {              verify(mockObj).              someCleanup(eq(...));           } }  
like image 28
singh30 Avatar answered Sep 21 '22 07:09

singh30


ExpectedException works by wrapping your entire test method in a try-catch block via a JUnit @Rule. When your code throws an exception, it goes up the stack to the nearest try/catch, which happens to be in the ExpectedException instance (which checks that it is the exception you're expecting).

In Java, if an uncaught exception occurs in a method, control will never return to statements later in that method. The same rules apply here: Control never returns to the statements in your test after the exception.

Technically, you could put the verifications in a finally block, but that tends to be a bad habit. EDIT: Your system-under-test might throw an unexpected exception, or no exception at all, which would give you a helpful failure message and trace; however, if that failure then causes your verifications or assertions to fail in the finally block, then Java will show that rather than a message about the unexpected exception or unexpected success. This can make debugging difficult, especially because your error will come from lines of code following the root cause of the error, incorrectly implying that the code above it succeeded.

If you really need to verify state after the exception, on a per-method basis, you can always revert back to this idiom:

@Test public void testExpectedException() {   MockedObject mockObj = mock(MockedObj.class);   MySubject subject = new MySubject(mockedObj);   try {     subject.someMethodThrowingException();     fail("Expected MyException.");   } catch (MyException expected) {     assertEquals("My exception message.", expected.getMessage());   }   verify(mockObj).someCleanup(eq(...)); } 

Update: With Java 8's lambda expressions, you can wrap a functional interface call in a try block concisely enough to be useful. I imagine support for this syntax will find its way into many standard testing libraries.

assertThrows(MyException.class,     () -> systemUnderTest.throwingMethod()); 
like image 96
Jeff Bowman Avatar answered Sep 20 '22 07:09

Jeff Bowman