So, you have two interfaces:
interface SettingsProvider {
Settings getSettings(String id);
}
and
interface InternalSettingsProvider extends SettingsProvider {
@Override
InternalSettings getSettings(String id);
}
You mock one of the second, and you stub the method:
InternalSettingsProvider mockProvider =
mock(InternalSettingsProvider.class);
when(mockProvider.getSettings(“anId”)).thenReturn(someSettings);
You run some code that only knows about SettingsProvider, not InternalSettingsProvider. This code calls getSettings(“anId”). You’re expecting it to then make use of someSettings so…
…you get a NullPointerException.
It turns out that, with reflection, it actually makes a difference whether you call getSettings() on SettingsProvider or on InternalSettingsProvider. Each interface results in a separate Method object.
When the SettingsProvider#getSettings() call comes in, the matching code looks at the Methods it has registered for stubbing, and it finds one for InternalSettingsProvider#getSettings(), but none for SettingsProvider#getSettings(). So it returns the default value, which for an object is null.
Luckily, the first workaround you might think of does actually do the trick.
when(((SettingsProvider) mockProvider)
.getSettings(“anId”)).thenReturn(someSettings);
I ran into this with Mockito, but I imagine it’ll come up in some other reflection-related contexts too.