0

I have been told that testing java exceptions' messages is a good thing, but it looks so much like redundancy that I cannot believe it.

Consider following fictional code:

public class PersonTooYoungException extends RuntimeException {

    private static final String MESSAGE = "%d years old is much too young to register";

    public PersonTooYoungException(Integer age) {
        super(format(MESSAGE, age));
    }
}


public class PersonValidator implements Validator<Person> {

    private static final int MINIMAL_AGE = 18;

    private Clock clock;

    public PersonValidator(Clock clock) {
        this.clock = clock;
    }

    @Override
    public void validate(Person person) {
        final int personAge = person.getAge(clock);
        if (personAge < MINIMAL_AGE) {
            throw new PersonTooYoungException(personAge);
        }
    }
}

and single test for it:

public class PersonValidatorTest {

    PersonValidator personValidator;

    @Before
    public void setUp() throws Exception {
        personValidator = new PersonValidator(new FixedClock(2016, JANUARY, 1));
    }

    @Test
    public void shouldThrowExceptionForYoungerThan18() throws Exception {
        // given
        LocalDate birthDate = LocalDate.of(1998, FEBRUARY, 1);
        Person person = new Person(birthDate, "Mike", "Trevin");

        // when
        Throwable exception = catchThrowable(() -> personValidator.validate(person));

        // then
        assertThat(exception)
                .isInstanceOf(PersonTooYoungException.class)
                .hasMessage("17 years old is much too young to register");
    }
}

There are some issues with this code, but the thing that makes me sick is a redundancy of PersonTooYoungException.MESSAGE.

This one could be solved by changing visibility of PersonTooYoungException.MESSAGE to public and then using format(MESSAGE, computedAge) to compare. I don't like this one since it requires me to expose MESSAGE just for test visibility.

Another solution is to check if exception message contains current age of person. In this case, it could probably pass, but there are other cases where exception message contains some important data (even more data) and simply calling contains does not work right since it may catch some other values.

On the other hand, if we don't test the message at all, we won't be able to check the code which does some logic.

My question does not concern this particular example and this is not only about exceptions. Is there a standard way of handling/testing such and similar code? What about the cases where exception message contains more data (like some property name or value)?

  • There are various opinions on how good are Java exceptions. Bruce Eckel, well-known C++ and Java expert (author of popular Thinking in Java and Thinking in C++ books) thinks that checked exceptions was bad idea which looked good in small example programs. And it will be shame to miss hilarious rant about object-obsession of Java: Execution in the Kingdom of Nouns. TL;DR: yes, I agree with your gut feeling. – Peter M. - stands for Monica Feb 3 '16 at 15:49
  • Why we should concern about fictional code / problems? Let's solve real things. – Dee Feb 3 '16 at 16:22
  • @Dee it's a "fictional" problem which often happens in real code. Would you share your opinion if I put here more extensive, production code with the same issue? – Maciej Dobrowolski Feb 3 '16 at 16:49
  • @Dee: Because sometimes, when you trying to dig a hole through the wall, the best way to solve problem is step back and take look: maybe there is a door nearby? – Peter M. - stands for Monica Feb 3 '16 at 16:49
3

I think the answer to your question depends on what the exception text string is going to be used for. Is it part of the documented interface for that class? If some other part of the program is going to use it (say to pass that error message back to the person entering the data), and/or it's part of the documented interface, then you absolutely need to test it. If all that's documented is that the PersonTooYoung exception will be thrown, then I'd say that first, you shouldn't have to test for anything in particular showing up, and second, any later part of the program depending on the message being there is incorrect, and that part of the program needs tests for a variety of different exception messages.

Beyond that, I think the answer is going to be "It depends." In this case, what's really important to test, if you feel the need to test the text of the exception message, is that it contains the number "17." I'd be reluctant to test the entire exception string, because you could have a failure of the test case if someone decides to reword the exception string without updating the test case. If you really want to be paranoid, create a few test cases for this, and verify the correct age is included each time.

For other exception messages, you may want to test for the exact text you care about.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.