What have we learned so far
Part 1 – What is Unit Testing?
https://www.onlyfullstack.com/what-is-unit-testing/
Part 2 – What is JUnit? How to use JUnit?
https://www.onlyfullstack.com/what-is-junit-how-to-setup-junit-in-eclipse/
Part 3 – Annotations used in JUnit
https://www.onlyfullstack.com/part-3-annotations-used-in-junit/
Part 4 – JUnit Assert Methods
https://www.onlyfullstack.com/junit-assert-methods/
Part 5 – Complete guide for Hamcrest JUnit
https://www.onlyfullstack.com/complete-guide-for-hamcrest-matchers/
How do you assert that a certain exception is thrown in JUnit 4 tests?
package com.onlyfullstack.unittesting.service; import org.apache.commons.lang3.StringUtils; /** * This class contains the business logic to throw an exception */ public final class ExceptionHandling { public String convertIntoUpperCase(String input) { if (StringUtils.isEmpty(input)) { throw new IllegalArgumentException("Empty value is passed."); } return input.toUpperCase(); } }
The convertIntoUpperCase() method will throw an IllegalArgumentException if an empty string is passed to the method.
There are 3 ways to assert a certain exception in Junit. Let’s write the unit test cases for it.
1. try-catch idiom
This idiom is one of the most popular ones because it was used already in JUnit 3. This approach is a common pattern. The test will fail when no exception is thrown and the exception itself is verified in a catch clause.
@Test public void convertIntoUpperCase_withInvalidInput_tryCatchIdiom() { try { exceptionHandling.convertIntoUpperCase(""); fail("It should throw IllegalArgumentException"); } catch (IllegalArgumentException e) { Assertions.assertThat(e) .isInstanceOf(IllegalArgumentException.class) .hasMessage("Empty value is passed."); } }
2. @Test expected annotation
When the exception wasn’t thrown you will get the following message: java.lang.AssertionError: Expected exception: java.lang.IllegalArgumentException
With this approach, you need to be careful though. Sometimes it is tempting to expect general Exception, RuntimeException or even a Throwable. And this is considered as a bad practice because your code may throw an exception in other places than you actually expected and your test will still pass!
One of the drawback of this approach is you can’t assert for the exception message.
@Test(expected = IllegalArgumentException.class) public void convertIntoUpperCase_withInvalidInput_testExpected() { exceptionHandling.convertIntoUpperCase(""); }
3. Junit @Rule
The same example can be created using ExceptedException rule. The rule must be a public field marked with @Rule annotation.
@Test public void convertIntoUpperCase_withInvalidInput_ExpectedExceptionRule() { exception.expect(IllegalArgumentException.class); exception.expectMessage("Empty value is passed."); exceptionHandling.convertIntoUpperCase(""); }
I find the above code more readable hence I prefer to use this approach.
When the exception isn’t thrown you will get the following message: java.lang.AssertionError: Expected test to throw (an instance of java.lang.IllegalArgumentException and exception with the message “Empty value is passed.”). Pretty nice.
But not all exceptions I check with the above approach. Sometimes I need to check only the type of the exception thrown and then I use @Test annotation.
Source Code
Download the source code of JUnit tutorial from below git repository :
unit-testing-and-integration-testing-with-spring-boot