I have the following, heavily simplified class:
public class MyClass
{
private MqttClient field;
public void test() throws MqttException
{
field = new MqttClient(null, null);
field.connect();
}
}
I am using Eclipse Paho's MqttClient
class.
I want to test the test
method with a UnitTest. In order to have control over the MqttClient
instance I want to mock the object. My test-class looks as follows:
public class TestMyClass
{
// Make sure we are running with the PowerMockAgent initialized
static
{
PowerMockAgent.initializeIfNeeded();
}
// Make sure we are using PowerMock
@Rule
public PowerMockRule rule = new PowerMockRule();
// Mocked MqttClient
@Mock
MqttClient field;
// MyClass-Object injected with mocks.
@InjectMocks
MyClass myClass = new MyClass();
@PrepareForTest(MyClass.class)
@Test
public void test() throws Exception
{
// Initialize our mocks from annotations
MockitoAnnotations.initMocks(this);
// Catch the "new MqttClient(null, null);"
PowerMockito.whenNew(MqttClient.class).withAnyArguments().thenReturn(field);
myClass.test();
}
}
When I execute my test I am met with the following error:
java.lang.NullPointerException
at test.java.test.MyClass.test(MyClass.java:13)
at test.java.test.TestMyClass.test(TestMyClass.java:45)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.powermock.modules.junit4.rule.PowerMockStatement.evaluate(PowerMockRule.java:73)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:538)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:760)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:460)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:206)
I can call any method on field
it is always a null-reference. My problem is I have no idea why this is the case.
I changed the type of field
to several other classes, including java.awt.point
and SerializationInstantiatorHelper
(in order to test if it has to do with MqttClient
being an external dependency) as well as several classes in my project, calling an appropriate method on those objects. In all those cases the problem did not exist and the test succeeded without any issues. The method on the mocked object is called and does nothing - just as I want it to.
Only when using the MqttClient
class this problem occurs. Or at least I did not find any other class yet to reproduce this problem.
I am in all honesty totally lost at this point. What makes the MqttClient
class special? Why can I seemingly not mock it like any other class? What did I miss?
//EDIT
I narrowed down the problem by creating a local version of MqttClient
, copying over the source code. In all honesty, I am even more confused now though. The class has three constructors with the following signatures:
1.)
public MqttClient( String serverURI,
String clientId) throws MqttException
2.)
public MqttClient( String serverURI,
String clientId,
MqttClientPersistence persistence) throws MqttException
3.)
public MqttClient( String serverURI,
String clientId,
MqttClientPersistence persistence,
ScheduledExecutorService executorService) throws MqttException
If one of those three constructors is removed, everything works. Any combination of the class with two of those three constructors is working just fine. As soon as all three constructors exist, the beforementioned error message appears. This leads me to the assumption it could have something to do with PowerMockito not finding the correct constructor? If so, how would that be avoidable?