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.