Junit 5: How to Assert an Exception Is Thrown

JUnit 5: How to assert an exception is thrown?

You can use assertThrows(), which allows you to test multiple exceptions within the same test. With support for lambdas in Java 8, this is the canonical way to test for exceptions in JUnit.

Per the JUnit docs:

import static org.junit.jupiter.api.Assertions.assertThrows;

@Test
void exceptionTesting() {
MyException thrown = assertThrows(
MyException.class,
() -> myObject.doThing(),
"Expected doThing() to throw, but it didn't"
);

assertTrue(thrown.getMessage().contains("Stuff"));
}

How to use jUnit 5 Assertions to check, whether exception message starts with a String?

The assertThrows() method returns an exception instance of the expected type (if any). You can then manually get a message from is and check if it starts with the string you desire.

Here is a sample from doc

@Test
void exceptionTesting() {
Exception exception = assertThrows(ArithmeticException.class, () ->
calculator.divide(1, 0));
assertEquals("/ by zero", exception.getMessage());
}

How do you assert that a certain exception is thrown in JUnit tests?

It depends on the JUnit version and what assert libraries you use.

  • For JUnit5 and 4.13 see answer https://stackoverflow.com/a/2935935/2986984
  • If you use assertJ or google-truth, see answer https://stackoverflow.com/a/41019785/2986984

The original answer for JUnit <= 4.12 was:

@Test(expected = IndexOutOfBoundsException.class)
public void testIndexOutOfBoundsException() {

ArrayList emptyList = new ArrayList();
Object o = emptyList.get(0);

}

Though answer https://stackoverflow.com/a/31826781/2986984 has more options for JUnit <= 4.12.

Reference :

  • JUnit Test-FAQ

How do I assert my exception message with JUnit Test annotation?

You could use the @Rule annotation with ExpectedException, like this:

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

@Test
public void shouldThrowRuntimeExceptionWhenEmployeeIDisNull() throws Exception {
expectedEx.expect(RuntimeException.class);
expectedEx.expectMessage("Employee ID is null");

// do something that should throw the exception...
System.out.println("=======Starting Exception process=======");
throw new NullPointerException("Employee ID is null");
}

Note that the example in the ExpectedException docs is (currently) wrong - there's no public constructor, so you have to use ExpectedException.none().

How to test that no exception is thrown?

You're approaching this the wrong way. Just test your functionality: if an exception is thrown the test will automatically fail. If no exception is thrown, your tests will all turn up green.

I have noticed this question garners interest from time to time so I'll expand a little.

Background to unit testing

When you're unit testing it's important to define to yourself what you consider a unit of work. Basically: an extraction of your codebase that may or may not include multiple methods or classes that represents a single piece of functionality.

Or, as defined in The art of Unit Testing, 2nd Edition by Roy Osherove, page 11:

A unit test is an automated piece of code that invokes the unit of work being tested, and then checks some assumptions about a single end result of that unit. A unit test is almost always written using a unit testing framework. It can be written easily and runs quickly. It's trustworthy, readable, and maintainable. It's consistent in its results as long as production code hasn't changed.

What is important to realize is that one unit of work usually isn't just one method but at the very basic level it is one method and after that it is encapsulated by other unit of works.

Sample Image

Ideally you should have a test method for each separate unit of work so you can always immediately view where things are going wrong. In this example there is a basic method called getUserById() which will return a user and there is a total of 3 unit of works.

The first unit of work should test whether or not a valid user is being returned in the case of valid and invalid input.

Any exceptions that are being thrown by the datasource have to be handled here: if no user is present there should be a test that demonstrates that an exception is thrown when the user can't be found. A sample of this could be the IllegalArgumentException which is caught with the @Test(expected = IllegalArgumentException.class) annotation.

Once you have handled all your usecases for this basic unit of work, you move up a level. Here you do exactly the same, but you only handle the exceptions that come from the level right below the current one. This keeps your testing code well structured and allows you to quickly run through the architecture to find where things go wrong, instead of having to hop all over the place.

Handling a tests' valid and faulty input

At this point it should be clear how we're going to handle these exceptions. There are 2 types of input: valid input and faulty input (the input is valid in the strict sense, but it's not correct).

When you work with valid input you're setting the implicit expectancy that whatever test you write, will work.

Such a method call can look like this: existingUserById_ShouldReturn_UserObject. If this method fails (e.g.: an exception is thrown) then you know something went wrong and you can start digging.

By adding another test (nonExistingUserById_ShouldThrow_IllegalArgumentException) that uses the faulty input and expects an exception you can see whether your method does what it is supposed to do with wrong input.

TL;DR

You were trying to do two things in your test: check for valid and faulty input. By splitting this into two method that each do one thing, you will have much clearer tests and a much better overview of where things go wrong.

By keeping the layered unit of works in mind you can also reduce the amount of tests you need for a layer that is higher in the hierarchy because you don't have to account for every thing that might have gone wrong in the lower layers: the layers below the current one are a virtual guarantee that your dependencies work and if something goes wrong, it's in your current layer (assuming the lower layers don't throw any errors themselves).

How to throw an exception based on some condition in Junit 5?

In Mockito ArgumentMatcher is a functional interface and you could use argThat matcher.

@Mock
private CustomerRepo customerRepo;

@Test
void updateCustomerThrowsException() {
doThrow(RuntimeException.class)
.when(customerRepo).save(argThat(customer -> customer.getId() == 5));

var customer = new Customer();
customer.setId(5);

assertThrows(RuntimeException.class, () -> updateCustomer(customer));
}

how to test that a method throws an exception junit5

Maybe you can try the following code:

@Test
public void tryThrowExceptionForInvalidRequest() throws Exception {

final String invalid = "Este es un request invalido";

InvalidInputRequestType exceptionThrown = Assertions.assertThrows(
InvalidInputRequestType.class,
() -> {
detector.detectForRequest(invalid);
}
);
assertEquals(invalid, exceptionThrown.getMessage());
}

Testing for the expected exception message with junit 5

Since Assertions.assertThrows returns instance of your exception you can invoke getMessage on the returned instance and make assertions on this message :

Executable executable = () -> sut.method(); //prepare Executable with invocation of the method on your system under test

Exception exception = Assertions.assertThrows(MyCustomException.class, executable); // you can even assign it to MyCustomException type variable
assertEquals(exception.getMessage(), "exception message"); //make assertions here

Junit5 verify if an exception was thrown during the execution

JUnit has no way of detecting a thrown-and-caught exceptions. It would require analyzing the execution, and while it would probably be technically feasible in some way, it would be counterproductive to implement such a complex mechanism.

In this case I'm wondering why does it matter to the test where the exception is thrown? In any case the test fails provided your test considers Optional.empty() return value as a failed test, although maybe it shouldn't be catching the exception at all. In this case if the test fails you have to do extra work to determine what went wrong, but you still got the important information: something went wrong.

If you feel it's important to know where the exception is happening, then the methods should most likely be tested separately, which requires redesigning/refactoring the code to be more easily testable.



Related Topics



Leave a reply



Submit