Explain Codes LogoExplain Codes Logo

Mockito test a void method throws an exception

java
mockito
unit-testing
exception-handling
Nikita BarsukovbyNikita Barsukov·Dec 10, 2024
TLDR

If you're looking to simulate an exception being thrown in a void method using Mockito, you should use the doThrow() method:

import static org.mockito.Mockito.*; // Mock YourClass YourClass mock = mock(YourClass.class); // Configure to throw MyException on method() call doThrow(MyException.class).when(mock).method(); // Call the method and brace for impact mock.method(); // Watch it explode! 💥

This code will trigger MyException whenever method() is invoked on mock.

When one scenario just isn't enough

Sometimes life isn't as simple as a method always throwing an exception whenever called. You might need to test multiple behaviors for a single method call. Fret not, you can chain doThrow() calls or use doNothing() for different metaphoric weather conditions in your test world.

// Prepping for a stormy day, then sunshine doThrow(RuntimeException.class) .doThrow(RuntimeException.class) .doNothing() .when(mock) .voidMethod();

This code makes voidMethod() throw RuntimeException twice then quietly does nothing - like a storm passing and the sun coming out. You never know what the weather is like in a unit test, do you?

Embracing the BDD style

The world of Mockito speaks Behavior Driven Development (BDD) too, so if you've got a glow in the dark BDD hat on, and going with doThrow() grosses you out, you're in luck! Say hello to willThrow():

import static org.mockito.BDDMockito.*; // Mockito in BDD style, 'cause why not? willThrow(MyException.class).given(mock).method();

This BDD style of Mockito promises the same explosions (i.e., exceptions) as the original doThrow() method.

Verifying the blast radius

After lighting up the metaphorical dynamite stick by calling a method on a mock, you should put your safety hat on and check whether the wanted exception was indeed thrown using JUnit's Assertions.assertThrows():

import static org.junit.jupiter.api.Assertions.assertThrows; // Ready to catch the dreaded MyException assertThrows(MyException.class, () -> mock.method()); // Caught it!

Just as promised, assertThrows() checks whether the MyException was thrown.

Giving your exception a backstory

When you want to make things more spicy and test some retry logic, you might want to throw exceptions multiple times before eloping with a successful execution:

doThrow(new NetworkException()) .doThrow(new NetworkException()) .doNothing() .when(networkDependencyClient).performNetworkAction();

It will simulate a dodgy network that recovers after a couple of reconnects. Just like my wi-fi when it's raining.

Cutting it short (Lambda way)

If brevity is the soul of wit, here's how you can use Lambda to be the Shakespeare of your code:

// JUnit 5 Lean, mean, byte-saving machine assertThrows(MyException.class, () -> { mock.methodThatThrows(); // To be or not to be (tested), that's the question.🎭 });

I saw you! (Verifying method calls)

Busted! You never slip past the keen eyes of verify(). Especially, when it comes to checking if your method had its moment of fame:

// Spy CCTV reporting for duty verify(mock).methodThatThrows(); // Gotcha!

When your exception loves drama (Parameterized exceptions)

If you want your exception to throw a tantrum with a specific message, you can use doAnswer to give more context. Let the diva speak its heart out!

doAnswer(invocation -> { throw new MyException("After all these years, finally, an exception!"); }).when(mock).methodThatThrows();

Mind your exceptions manners

When playing with exceptions, make sure to be polite and stick to RuntimeExceptions and other unchecked exceptions. Unless you're dealing with the aristocracy of the exception world - the checked exceptions. Then put on your polite gloves and deal accordingly!

Taming the wild corner cases

Finally, while we want our tests to check our code's functionality, we should also prepare for the wild, unannounced, billingClientHasGoneRogueException. Handling such exceptions gracefully will ensure your tests won't crash on these potholes, resulting in false negatives.