Setting private fields of a class for unit testing

In this post under Powermock, I will with example show how to set private fields of a class for unit testing.

For example, consider you have a class as shown below to be tested

Class To Be Tested


package package5;

import java.util.Date;
import java.util.Random;

public class Example5 {
    private Random random = new Random();

    public Date createDate() {
        int result = random.nextInt(10);
        if(result % 2 == 0) {
            return new Date();
        } else {
            return null;
        }
    }
}

Your goal is to unit test “createDate” method. This method based on random value generated creates an instance of “Date” class.

So if the random value in “result” variable is even it creates a “Date” object or else return null.

To unit test this we cannot depend upon on the Random object (created inside the class) to return even number first and then odd number.

We have to mock the Random object and program the “nextInt” method to return even number first and then odd number second. If we do this we can test the “createDate” method for both positive (when the “result” is even number) and negative (when the “result” is odd number) scenario.

But even if we mock the Random object, there is no setter method in the Example5 class, to set the mocked Random object. We cannot modify the Singleton class to make our test class work. It is wrong.

So how to test “createDate” method. The solution is taking help of “Whitebox” class under “org.powermock.reflect” package.

Below is the test class

Test Class


1  package package5;
2  
3  import static org.junit.Assert.assertNotNull;
4  import static org.junit.Assert.assertNull;
5  import static org.mockito.ArgumentMatchers.anyInt;
6  import static org.mockito.Mockito.when;
7  
8  import java.util.Date;
9  import java.util.Random;
10 
11 import org.junit.Test;
12 import org.mockito.Mockito;
13 import org.powermock.reflect.Whitebox;
14 
15 public class Example5Test {
16     @Test
17     public void testEvaluateRule() {
18         Example5 example5 = new Example5();
19         Random random = Mockito.mock(Random.class);
20         Whitebox.setInternalState(example5, "random", random);
21         
22         when(random.nextInt(anyInt())).thenReturn(2);
23         Date date = example5.createDate();
24         assertNotNull(date);
25         
26         when(random.nextInt(anyInt())).thenReturn(3);
27         date = example5.createDate();
28         assertNull(date);
29     }
30 }

In the above code, at line 18, we are creating an instance of Example5 class (the class to be tested).

At line 19, we are creating a mock of Random class.

At line 20, we take the help of “Whitebox” class’s static “setInternalState” method to set the private “random” field in Example5 class. We call the “setInternalState” method and pass “example5” object, the field name (in this case “random” string), and the value to be set (in this case mock “random” object).

At line 22, we program the mock “random” object’s “nextInt” method to return 2 (an even number) to test the positive scenario.

At line 26, we program the mock “random” object’s “nextInt” method to return 3 (an odd number) to test the negative scenario.

So in this way with the help of Whitebox class we can set private fields of a class for unit testing purposes.

Leave a Reply