177

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.

2
  • 1
    This link might be helpful to you stackoverflow.com/questions/13645571/… Commented Mar 23, 2016 at 9:20
  • 3
    You should refactor your code so that you can pass in a mock for Person. Options include adding a constructor to do this, or adding a setter method. Commented Mar 23, 2016 at 9:23

9 Answers 9

151

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.

Sign up to request clarification or add additional context in comments.

13 Comments

I'm spying my target object because of other reasons and in this case when my object is spy, I cannot set internal state this way.
Why not? I am using it with spies. Create a Person instance. Stub whatever needs stubbing, then set it on your Test instance.
Warning: Whitebox is in the internal package and does not seem to work anymore on Mockito 2.6.2.
You can use FieldSetter.setField(). I've given an example below for the same.
@Ralf Because changing a reference name in Java should always result in a compilation error.
|
126

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

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

4 Comments

Great! Might help to link to this article and maybe include the dependencies one needs from it: baeldung.com/spring-reflection-test-utils
build.gradle.kts: testImplementation("org.springframework:spring-test:5.1.2.RELEASE")
This is not useful for JUnit 5 or spring: 2.4.2 version
@SolankiVaibhav why not?
98

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.

6 Comments

FieldSetter is not available anymore in Mockito 2.x.
@Ralf I'm using version mockito-core-2.15.0. It's available there. static.javadoc.io/org.mockito/mockito-core/2.0.15-beta/org/…. Still beta though.
@RajKumar the Class#getDeclaredField accepts single param, so the parens need to look like thisFieldSetter.setField(underTest, underTest.getClass().getDeclaredField("person"), mockedPerson);. That was how I got it wrong and thought might be a good idea to fix it in your example. Thanks for replying.
using internal API is not the best idea
I don't understand, how could this work with private field? underTest.getClass().getDeclaredField("person") will throw NoSuchFieldException I think.
|
36

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

1 Comment

Your explanation talks about the mockStatic function, but that is not represented in your code example. Should the code example have the mockStatic call, or is that not required for constructors?
12

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

Comments

11

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); // ... } 

Comments

10

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 } 

Comments

6

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.

Comments

5

commons-lang3

import org.apache.commons.lang3.reflect.FieldUtils; FieldUtils.writeField(object, fieldName, value, true); 

1 Comment

(from review) could you add a little more about how this works?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.