Issue
I have a unit test with a real object (Data data) and a boolean value (boolean required) as input.
mockTest(Data data, boolean required)
In my code I have
data.getObjectA().getPara1();
data.getObjectA().getPara2();
And I'm trying to mock the return value of data.getObjectA().getPara1() to the booelan in the input
But below won't work:
Mockito.when(data.getObjectA().getPara1()).thenReturn(required);
Or
Data dataSpy = Mockito.spy(data);
Mockito.when(dataSpy.getObjectA().getPara1()).thenReturn(required);
Mockito.when(dataSpy.getObjectA().getPara2()).thenCallRealMethod();
They either throw NullPointerException or Type errors
What is the correct way of mocking/spying it? I need to mock the return of para1 and keep para2 the real value.
Solution
If you want to override ObjectA's behavior, then the instance that data
returns needs to be a mock or spy. Fundamentally you have three choices:
Use a spy
As in Dawood's answer:
Data dataMock = Mockito.mock(Data.class);
ClassA objectASpy = Mockito.spy(objectA);
when(dataMock.getObjectA()).thenReturn(objectASpy);
when(objectASpy.getPara1()).thenReturn(required); // note 1
If you want getPara1()
to return the same result for any internal calls within objectASpy
, this is the way to go.
Use delegatesTo
This opts into a delegation-based behavior for Mockito, rather than overriding as it usually does.
Data dataMock = Mockito.mock(Data.class);
ClassA objectAMock = Mockito.mock(ObjectA.class, delegatesTo(objectA));
when(dataMock.getObjectA()).thenReturn(objectAMock);
when(objectASpy.getPara1()).thenReturn(required); // note 1
If you only want getPara1()
to return required
on the outside calls, but have objectASpy
return its original value for its internal calls, you could use this technique.
Use deep stubbing
Mockito does have a feature that would allow for your current syntax:
Mockito.when(dataSpy.getObjectA().getPara1()).thenReturn(required);
Mockito.when(dataSpy.getObjectA().getPara2()).thenCallRealMethod();
This feature is called returning deep stubs, and is best for when an object like dataSpy
here represents a tree of very straightforward objects. That said, heed its warning:
WARNING: This feature should rarely be required for regular clean code! Leave it for legacy code. Mocking a mock to return a mock, to return a mock, (...), to return something meaningful hints at violation of Law of Demeter or mocking a value object (a well known anti-pattern).
Note 1
The line when(objectASpy.getPara1()).thenReturn(required);
will actually call objectASpy.getPara1()
. This might be fine as long as the object doesn't throw an exception and doesn't have side effects, but you can avoid that behavior with doVerb
syntax so Mockito can see ahead of the call that you're starting to stub.
Note that unlike when().thenReturn()
syntax, the when
below only contains the mock instead of the full mock method call.
doReturn(required).when(objectASpy).getPara1();
Answered By - Jeff Bowman
Answer Checked By - David Goodson (JavaFixing Volunteer)