1

In my TestNG unit tests I have a scenario, where I want to test, that an exception was thrown, but also I want to test that some method was not called on mocked sub-component. I came up with this, but this is ugly, long and not well readable:

@Test
public void testExceptionAndNoInteractionWithMethod() throws Exception {

    when(subComponentMock.failingMethod()).thenThrow(RuntimeException.class);

    try {
        tested.someMethod(); //may call subComponentMock.methodThatShouldNotBeCalledWhenExceptionOccurs
    } catch (RuntimeException e) {
        verify(subComponentMock, never()).methodThatShouldNotBeCalledWhenExceptionOccurs(any());
        return;
    }

    fail("Expected exception was not thrown");
}

Is there any better solution to test both Exception and verify() metod?

Michal Krasny
  • 5,434
  • 7
  • 36
  • 64
  • If you use TestNG then for expected exceptions you should use `expectedExceptions` attribute of the `@Test` annotation instead of using `try catch` blocks. – Jagger May 18 '16 at 09:15
  • But in that case I'm not able to use verify(), because test code will never get there – Michal Krasny May 18 '16 at 09:16
  • 2
    Possible duplicate of [Mockito How to mock and assert a thrown exception?](http://stackoverflow.com/questions/16243580/mockito-how-to-mock-and-assert-a-thrown-exception) – krokodilko May 18 '16 at 09:17
  • @kordirko thanks for the link, but the only usable answer contains limitation "Only Mockito up to 1.10.8 is supported". However I'll give it chance, even if my Mockito version is 1.10.19 – Michal Krasny May 18 '16 at 09:20
  • 1
    @Michal If I were you I would separate those two concerns. First I would check if the exception was thrown by using the `expectedExpections` attribute. Then the second aspect of whether a method was never called I would put in a separate test with defined dependency using `@Test(dependsOnMethods = "testExceptionAndNoInteractionWithMethod")` to the first one (you will probably want to rename this dependency method to something like `testExpection`). I see that you store the `subComponentMock` as a test class attribute anyway, so this should not be a problem for you at all. – Jagger May 18 '16 at 09:23

3 Answers3

2

We decided use Assertions framework.

when(subComponentMock.failingMethod()).thenThrow(RuntimeException.class);

Assertions.assertThatThrownBy(() -> tested.someMethod()).isOfAnyClassIn(RuntimeException.class);

verify(subComponentMock, never()).methodThatShouldNotBeCalledWhenExceptionOccurs(any());
Michal Krasny
  • 5,434
  • 7
  • 36
  • 64
1

I would separate those two concerns by creating two tests and making use of annotation attributes expectedExceptions and dependsOnMethods.

@Test(expectedExceptions = { RuntimeExpcetion.class } )
public void testException() {
    when(subComponentMock.failingMethod()).thenThrow(RuntimeException.class);
    tested.someMethod(); //may call subComponentMock.methodThatShouldNotBeCalledWhenExceptionOccurs
}

@Test(dependsOnMethods = { "testException" } )
public void testNoInteractionWithMethod() {
    verify(subComponentMock, never()).methodThatShouldNotBeCalledWhenExceptionOccurs(any());
}

For me it looks neater. You get rid of try catch block and unnecessary fail method invocation.

Jagger
  • 10,350
  • 9
  • 51
  • 93
  • 1
    Thank you for this answer. A fierce discussion started in our team, I will get back after. – Michal Krasny May 18 '16 at 10:49
  • 1
    So, we finally found, what we were looking. This solution brings one thing, which we did not like - a dependency between tests. We believe, that tests should be independent. The solution we chose is in my answer. – Michal Krasny May 20 '16 at 08:07
1

There is one more convenient way , which nobody mentioned .

https://javadoc.io/doc/org.testng/testng/latest/org/testng/Assert.html

For example :

    @Test
    public void testAddEntitlementWithServerException() {
        OrgId orgId = OrgId.fromString("ef9b0be1-48c5-4503-bf95-d5cf1f942f46");
        String failureMessage = "Error message";

        // mock exception behaviour
        when(scimOrgClient.addEntitlement(orgId, "", true, null)).thenThrow(new ClientException(HttpStatus.SC_BAD_REQUEST, "Error message"));

        ServerException serverException = expectThrows(ServerException.class, () -> squaredOfferService.addEntitlement(orgId, "", true, null));

        assertEquals(serverException.getMessage(), failureMessage);
        verify(scimOrgClient, times(1)).addEntitlement(orgId, "", true, null);
    }
Prashant Singh
  • 426
  • 7
  • 17