5

It's a good practice to divide test cases into 3 sections: Given, When, Then.

But in JUnit common way to handle exceptions is using ExpectedException @Rule.

The problem is ExpectedException::expect() must be declared before //when section.

public class UsersServiceTest {

// Mocks omitted    

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

@Test
public void signUp_shouldCheckIfUserExistsBeforeSign() throws ServiceException {
    // given - its ok
    User user = new User();
    user.setEmail(EMAIL);
    when(usersRepository.exists(EMAIL)).thenReturn(Boolean.TRUE);

    // then ???
    thrown.expect(UserAlreadyExistsServiceException.class);

    // when???
    usersService.signUp(user);

}
}

Does anyone know some good convention or library for better handling exceptions in tests?

Michał Mielec
  • 1,582
  • 1
  • 14
  • 38
  • I'm not sure what your question is. What do you want as end-goal? – Tunaki Nov 21 '15 at 19:14
  • 1
    Problem is I declare exception checking (then section) before calling tested method (when section). I am asking how to do this in best way. – Michał Mielec Nov 21 '15 at 19:21
  • Define "best". I don't see the problem here. – Tunaki Nov 21 '15 at 19:22
  • 2
    According best conventions / practices of TDD/BDD – Michał Mielec Nov 21 '15 at 19:23
  • Another idea is to declare thrown.expect() in given section. – Michał Mielec Nov 21 '15 at 19:24
  • @MichałMielec I would say that the practice of Given/When/Then is for human-readable BDD cases, and exception handling is not human readable. http://stackoverflow.com/a/2500263/2646526 – heenenee Nov 24 '15 at 07:14
  • Well, would probably be easy enough to write a custom JUnit runner that ignores that @Test annotation but uses something like @Given (instead @Before), @When (instead of @Test) and @Then (new). The @Then method could accept, for example, an exception or the return value of the @when method, which would allow to write... `@Then public void then(Exception ex) { assertThat(ex, notNull()); }` You could make it pretty dynamic to allow various signatures. But honestly, I don't quite see the use of the whole thing. – Florian Schaetz Nov 25 '15 at 11:27
  • JBehave also doesn't seem to have a good system for that, since all examples I see are based on catching the exception and storing it somewhere to check in the `then` method, which is pretty ugly, if you ask me. – Florian Schaetz Nov 25 '15 at 11:31
  • Looking forward for the answer to this question. – Eido95 Aug 26 '18 at 15:35
  • You might find you answer in the following article: [8 Ways of Handling Exceptions in JUnit](http://blog.codeleak.pl/2017/06/testing-exceptions-with-junit-5.html). – Eido95 Aug 26 '18 at 15:59

2 Answers2

3

First of all, I think your tests are ok even if some don't exactly follow the given/when/then sequence, but good for you if you want to standardize the organization of your tests for improved readability.

There are lots of valid ways to expect an exception in JUnit, as described in this StackOverflow page. I think the one that seems to fit in with the given/when/then organization would be:

@Test
public void signUp_shouldCheckIfUserExistsBeforeSign() throws ServiceException {

    // GIVEN
    User user = new User();
    user.setEmail(EMAIL);
    when(usersRepository.exists(EMAIL)).thenReturn(Boolean.TRUE);

    // WHEN 
    try {
        usersService.signUp(user);

    // THEN
        // expecting exception - should jump to catch block, skipping the line below:
        Assert.fail("Should have thrown UserAlreadyExistsServiceException");         
    }catch(UserAlreadyExistsServiceException e) {
        // expected exception, so no failure
    }
    // other post-sign-up validation here
}
Community
  • 1
  • 1
aro_tech
  • 1,103
  • 7
  • 20
0

You can define the type of exception you expect in the Test annotation thus:

@Test(expected=NullPointerException.class)
public void npeThrownWhenFooIsNull() {
    String foo = null;
    foo.contains("nothing");
}

or, if you want to check the details of the exception that is thrown:

@Test
public void npeIsThrownAndContainsNullMessageWhenFooIsNull() {
    String foo = null;
    try {
        foo.contains("nothing");
        fail();
    } catch (NullPointerException npe) {
        assertNull(npe.getMessage());
    }
}

I find this a preferable means of testing exception handling

robjwilkins
  • 5,462
  • 5
  • 43
  • 59