Mockito: Mock private field initialization
JavaMockitoJunit4PowermockitoJava Problem Overview
How I can mock a field variable which is being initialized inline?
class Test {
private Person person = new Person();
...
public void testMethod() {
person.someMethod();
...
}
}
Here I want to mock person.someMethod()
while testing the Test.testMethod()
method for which I need to mock initialization of person
variable. Any clue?
Edit: I'm not allowed to modify Person class.
Java Solutions
Solution 1 - Java
Mockito comes with a helper class to save you some reflection boiler plate code:
import org.mockito.internal.util.reflection.Whitebox;
//...
@Mock
private Person mockedPerson;
private Test underTest;
// ...
@Test
public void testMethod() {
Whitebox.setInternalState(underTest, "person", mockedPerson);
// ...
}
Update: Unfortunately the mockito team decided to remove the class in Mockito 2. So you are back to writing your own reflection boilerplate code, use another library (e.g. Apache Commons Lang), or simply pilfer the Whitebox class (it is MIT licensed).
Update 2: JUnit 5 comes with its own ReflectionSupport and AnnotationSupport classes that might be useful and save you from pulling in yet another library.
Solution 2 - Java
Pretty late to the party, but I was struck here and got help from a friend. The thing was not to use PowerMock. This works with the latest version of Mockito.
Mockito comes with this org.mockito.internal.util.reflection.FieldSetter
.
What it basically does is helps you modify private fields using reflection.
This is how you use it:
@Mock
private Person mockedPerson;
private Test underTest;
// ...
@Test
public void testMethod() {
FieldSetter.setField(underTest, underTest.getClass().getDeclaredField("person"), mockedPerson);
// ...
verify(mockedPerson).someMethod();
}
This way you can pass a mock object and then verify it later.
Here is the reference.
Solution 3 - Java
In case you use Spring Test try org.springframework.test.util.ReflectionTestUtils
ReflectionTestUtils.setField(testObject, "person", mockedPerson);
Solution 4 - Java
I already found the solution to this problem which I forgot to post here.
@RunWith(PowerMockRunner.class)
@PrepareForTest({ Test.class })
public class SampleTest {
@Mock
Person person;
@Test
public void testPrintName() throws Exception {
PowerMockito.whenNew(Person.class).withNoArguments().thenReturn(person);
Test test= new Test();
test.testMethod();
}
}
Key points to this solution are:
-
Running my test cases with PowerMockRunner:
@RunWith(PowerMockRunner.class)
-
Instruct Powermock to prepare
Test.class
for manipulation of private fields:@PrepareForTest({ Test.class })
-
And finally mock the constructor for Person class:
PowerMockito.mockStatic(Person.class);
PowerMockito.whenNew(Person.class).withNoArguments().thenReturn(person);
Solution 5 - Java
Following code can be used to initialize mapper in REST client mock. The mapper
field is private and needs to be set during unit test setup.
import org.mockito.internal.util.reflection.FieldSetter;
new FieldSetter(client, Client.class.getDeclaredField("mapper")).set(new Mapper());
Solution 6 - Java
Using @Jarda's guide you can define this if you need to set the variable the same value for all tests:
@Before
public void setClientMapper() throws NoSuchFieldException, SecurityException{
FieldSetter.setField(client, client.getClass().getDeclaredField("mapper"), new Mapper());
}
But beware that setting private values to be different should be handled with care. If they are private are for some reason.
Example, I use it, for example, to change the wait time of a sleep in the unit tests. In real examples I want to sleep for 10 seconds but in unit-test I'm satisfied if it's immediate. In integration tests you should test the real value.
Solution 7 - Java
if u are using spring boot test and cant find neither of WhiteBox
, FeildSetter
; u can simply use org.springframework.test.util.ReflectionTestUtils
this is an example:
import org.springframework.test.util.ReflectionTestUtils;
//...
@Mock
private Person mockedPerson;
private Test underTest;
// ...
@Test
public void testMethod() {
ReflectionTestUtils.setField(underTestObject, "person", mockedPerson);
// ...
}
Solution 8 - Java
The best way until now, I think that is
org.springframework.test.util.ReflectionTestUtils
Im about to mock the private String mockField
in FooService.class inside FooServiceTest.java
FooService.java:
@Value("${url.image.latest}")
private String latestImageUrl;
FooServiceTest.java:
@InjectMocks
FooService service;
@BeforeEach
void setUp() {
ReflectionTestUtils.setField(service, // inject into this object
"latestImageUrl", // assign to this field
"your value here"); // object to be injected
}