Explain Codes LogoExplain Codes Logo

Mockito - NullpointerException when stubbing Method

java
mockito
unittesting
best-practices
Alex KataevbyAlex Kataev·Nov 19, 2024
TLDR

Correctly tackling a NullPointerException during Mockito stubbing requires proper initialization of the target class with mock() or spy(). Declare the expected behaviour as follows:

MyClass myClassMock = mock(MyClass.class); when(myClassMock.myMethod()).thenReturn(myExpectedValue);

To avoid NullPointerException, inject mocks into the test subject and ensure all dependencies are non-null before stubbing. Use @RunWith(MockitoJUnitRunner.class) or initMocks(this) for supporting annotations.

For matching method parameters, replace any() with more precise and type-specific matchers such as anyInt(), anyLong() and others.

Precisely matching arguments

Utilizing specific argument matchers

When stubbing, employing specific matchers like anyInt() guarantees proper management of parameters, shielding you from unwanted NullPointerExceptions:

// Correct usage of specific argument matchers when(myClassMock.someMethod(anyInt())).thenReturn(myExpectedValue); // The method now accepts any integer without throwing a tantrum!

Annotations ease Mockito setup

The effective use of @InjectMocks, @RunWith(MockitoJUnitRunner.class), and @Before annotations ensures timely initialization of mocks before each test, thereby reducing the risk of null references.

Minimizing deep stub overuse

The RETURNS_DEEP_STUBS strategy can be handy but it's not a panacea. It simplifies stubbing chained calls but can create overly complex stubs that may obscure test intent and increase maintenance struggles.

Mastering Mockito stubbing

Conquering chained methods stubbing

RETURNS_DEEP_STUBS could be your secret weapon for elegantly stubbing chained calls and removing cumbersome intermediate stubs:

// Leveraging Mockito.RESULTS_DEEP_STUBS for stubbing chained calls when(myClassMock.someMethod().anotherMethod()).thenReturn(myExpectedValue); // It's like Mockito inception.

Safeguard initialization of mocks

Uninitialized mocks are a gateway to NullPointerException. Proper setup using @Before and MockitoAnnotations.initMocks(this) ensures mock safety.

@Before public void prepareMocks() { MockitoAnnotations.initMocks(this); }

Parameter types need your attention!

Understanding the expected parameter type of the mocked method is paramount. Putting any() where anyString() should be could end up in a battle against exceptions.

Confirming mock conduct

Assert and verify your beliefs

Including assert and verify statements let's you validate that your mocks are cooperative. It helps catch any surprise interactions:

// Verifying mock interactions verify(myClassMock).myMethod(anyInt()); // This is your lie detector test for the mock.

Don't set a trap with setters on mocks

Avoid redundant actions like using setters on mocks. Remember, mocks are not known for retaining state.

Correct Test annotations are your friends

A misplaced @Test annotation from testNG instead of JUnit could lead to unexpected results. Beware!

Careful import scrutiny

Importing JUnit annotations correctly is like checking your gear before a space launch. It prevents subtle mistakes that could lead to failing tests.