0

This seems like it should be simple but I'm running around in circles.

I have:

@Mock
SimpleAbstractCacheWithInputs<Key, Value, Inputs> underlyingCache;

I then try to set up a call on the cache in setup():

when(underlyingCache.getOrCreate(usdgbpKey)).thenReturn(usdgbpCfi);

But this throws a null pointer exception from within getOrCreate() because it's trying to execute the actual code in the real object, not mocked at all, and that isn't set up.

But I don't want to ever run getOrCreate real code, I just want it to return the mocked value!

So how do I do this without having to set up everything inside underlyingCache that I'm never going to use in order to mock this one method call?

Tim B
  • 40,716
  • 16
  • 83
  • 128
  • Is underlyingCache a member object of the class you're testing? Are you injecting the mock into the class you're testing? Could you post more of the test class? – blur0224 Jun 07 '16 at 14:15
  • underlyingCache is being passed as a constructor parameter to the class I'm testing. However I never even get to that stage as I can't use when() to set up underlyingCache. ... I've just managed to work around this problem by switching to mocking the interface rather than the cache object. I'd still like to know how to solve this in future though. – Tim B Jun 07 '16 at 14:17
  • From what you have posted it looks right, but the behavior definitively sounds like the class is not being mocked. I'd need to see a more complete example to venture a guess as to why. Also this might be useful since you're dealing with an abstract class http://stackoverflow.com/questions/1087339/using-mockito-to-test-abstract-classes – blur0224 Jun 07 '16 at 14:22
  • 1
    Please post more of your test class. Maybe you forgot something simple, like: not using `@RunWith(MockitoJUnitRunner.class)` or doing something wrong with setting up the mock. – Jesper Jun 07 '16 at 14:23

1 Answers1

0

If you were concerned about the behavior of a spy or already-stubbed object, I would recommend this syntax, which doesn't rely on calling the mocked object:

doReturn(usdgbpCfi).when(underlyingCache).getOrCreate(usdgbpKey);

...but that all seems right. If you're using the @Mock annotation, then the entire object should be mocked, or null if you've forgotten a Mockito runner/rule/initialization.

There are a few cases where mocking would fail and you get the actual behavior instead:

  1. If the method is final, because then Mockito can't override the method (through a proxy).
  2. If the class is final, because then Mockito can't override the class (through a proxy).
  3. If the class has complicated access semantics, such as a public nested class that accesses private parent methods, because the Java compiler may rewrite the method call through a synthetic method that Mockito can't (easily) mock.
Jeff Bowman
  • 90,959
  • 16
  • 217
  • 251