Mockito: Mock private field initialization

北城以北 提交于 2019-11-27 01:00:08

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.

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.

Reference:

https://www.codota.com/code/java/methods/org.mockito.internal.util.reflection.FieldSetter/set

Arun

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:

  1. Running my test cases with PowerMockRunner: @RunWith(PowerMockRunner.class)

  2. Instruct Powermock to prepare Test.class for manipulation of private fields: @PrepareForTest({ Test.class })

  3. And finally mock the constructor for Person class:

    PowerMockito.mockStatic(Person.class); PowerMockito.whenNew(Person.class).withNoArguments().thenReturn(person);

In case you use Spring Test try org.springframework.test.util.ReflectionTestUtils

 ReflectionTestUtils.setField(testObject, "person", mockedPerson);

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());

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.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!