Mockito: Mock private field initialization
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);
Mocking a Private Variable that is Assumed to Exist
After a lot more hunting around and looking at all the options Mockito/Powermock had to offer, I found the solution (which I will share in case others run into this same issue).
When you have private member variables that are never initialized (and just assumed created in other places), you can use the @InjectMocks
annotation to "inject" Mocks you want into your class you are testing.
- Add a variable in your test class for the class you are testing, and give it the annotation
@InjectMocks
(org.Mockito.InjectMocks). - Use
@Mock
annotations to setup the mocks you want to inject. Use the@Mock (name = "privateVariableNameHere")
name property to map the Mock object to the private variable inside your class you are testing. - In either a setup function or before you call your class, initialize the mocks. The easiest way I have found is to use a "setup" method with the
@Before
annotation. Then inside there callMockitoAnnotations.initMocks(this);
to quickly initialize anything with the@Mock
annotation. - Define your Mock functionality in your test method (before calling the method you are testing).
- Using the
@InjectMock
object, call your method you are testing... the mocks SHOULD be hooked in and working as defined in the earlier steps.
So for the example class I use above, the code to test/mock would have Connection
returned as a mock which you can do whatever with. Based on the example above in my question, this is what the code would look like:
@RunWith(PowerMockRunner.class)
@PrepareForTest({/* Static Classes I am Mocking */})
public class ExampleTest {
@Mock (name = "queueFactory") //same name as private var.
QueueConnectionFactory queueFactoryMock;
@Mock
Connection connectionMock; //the object we want returned
@InjectMocks
Example exampleTester; //the class to test
@Before
public void setup(){
MockitoAnnotations.initMocks(this); // initialize all the @Mock objects
// Setup other Static Mocks
}
@Test
public void testTestMe(){
//Mock your objects like other "normally" mocked objects
PowerMockito.when(queueFactoryMock.createConnection()).thenReturn(connectionMock);
//...Mock ConnectionMock functionality...
exampleTester.testMe();
}
}
Initialize private field in mocked class
In your case you could use a Spy instead of a mock.
This would trigger the constructor and assign an empty list to the private variable thus escaping the NPE:
private UsersLoader loader;
@Before
public void setUp() {
loader = spy(new UsersLoader());
}
Now you do not need make this call:
doCallRealMethod().when(loader).loadExternalUsers(anyBoolean());
Just keep in mind that you need to mock any methods that do not need to be triggered as implemented.
Mockito not mocking private variables using @Spy
myObject = new MyObject();
- this is the root of the problem. Mockito
instantiates the mock for you, but you're replacing the mock with your own myObject
instance, what leads to NPE (obviously, the listOfStrings
is null in your newly instantiated object).
That how it should work:
@RunWith(MockitoJUnitRunner.class)
public class MyObjectTest {
// Don't do this with List!
// Type 'List' is an interface and it cannot be spied on.
@Spy
private ArrayList<String> listOfStrings;
@InjectMocks
private MyObject myObject;
@Before
public void before() {
listOfStrings.addAll(List.of("test", "test2"));
}
@Test
public void testCallListOfStrings() {
Mockito.doReturn(new ArrayList().stream()).when(listOfStrings).stream();
myObject.callListOfStrings();
}
}
Output:
test
test2
Java Mockito - How Mock private member that initializing in the constructor
If you want to mock the instance of ReportCollector
which is used by BasicReportManager
then you must inject it when your test case creates BasicReportManager
. For example:
ReportCollector reportData = Mockito.mock(ReportCollector.class);
Sendable sendable = Mockito.mock(Sendable.class);
Mockito.when(reportData.collect()).thenReturn(sendable);
BasicReportManager basicReportManager = new BasicReportManager("1", reportData);
// now your test invocation on BasicReportManager will use the mocked instance of ReportCollector
You could consider al alternative like providing a factory for ReportCollector
but this simple fact remains: in order to let BasicReportManager
use a mocked instance of ReportCollector
in your test case you have to be able (somehow!) to provide BasicReportManager
with that mocked instance.
Setting private field in abstract super class using mockito
Your difficulties to such things can be seen as a symptom.
You can decide that the cure is to spent hours until you get the mocking parts to circumvent around that problem.
Whereas the other option is: understand that the given design is deficient:
- sub classes should absolutely not care about private fields in super classes. The whole point of private is to make things an "implementation detail" that no other class should know or care about
- Worse: by putting up a second private field with the same name, you just added to that confusion. Those will be to different private fields; there is no "overriding" or "polymorphism" here.
In the end, you probably do not understand how to properly design a solution that uses inheritance and abstract base classes. You should thus step back, and think for example, if a solution like this helps:
public abstract class Base {
protected abstract Configuration getConfiguration();
public final void doSomething() {
... calls getConfiguration() to do its jobs
}
}
and then:
public abstract class Subclass extends Base {
protected Configuration getConfiguration() {
return whatever
As a rule of thumb: clean, straight-forward, non-surprising designs can most often be unit tested simply by using dependency injection and one mock here and another one there. As soon as you have to look into all these complex "solutions"; such as mocking super-class methods/fields; or mocking static methods, ... you are already suffering from a bad design; and instead of fixing that problem; you try to work around it.
That will not help you in the long run. Because the real problem is the "smelly" design in your production code.
Related Topics
Do We Need Volatile When Implementing Singleton Using Double-Check Locking
What Do Curly Braces in Java Mean by Themselves
Add Jlabel with Image to Jlist to Show All the Images
Loss of Precision - Int -> Float or Double
Scanner Only Reads File Name and Nothing Else
Calling Base Class Overridden Function from Base Class Method
How to Draw a Crisp, Opaque Hairline in Javafx 2.2
What Is the Use of Pattern.Quote Method
Optimizing Memory Leakage in Javafx
Bouncy Castle:Pemreader => Pemparser
Setting Print Size of a Jlabel and Put a Jradiobutton on the Print
Differencebetween Synchronized on Lockobject and Using This as the Lock
What Does a Jvm Have to Do When Calling a Native Method
Why Functional Interfaces in Java 8 Have One Abstract Method
When Using Mokito, Differencebetween the Actual Object and the Mocked Object