Gerko Ford Gerko Ford - 2 months ago 9
Java Question

How to call a method from a mocked interface using EasyMock

I am writing a Junit unit test for a class and I am getting a java.lang.NullPointerException on the following line :

expect(lineConfigurationHandlerMock.getDeviceControlHandler().getDeviceParameters(item1)).andReturn(myDeviceParameters);


I think (i am not sure though) that it has something to do with the method (getDeviceControlHandler) that I am calling from within the mocked interface . Because I have added this line of code before the submentioned line:

Assert.assertNotNull(comLineConfigurationHandlerMock.getDeviceControlHandler());


And I am having the following error:


java.lang.AssertionError


I am stuck here and really need some help.

Thanks in Advance.

The thrown Exception:

java.lang.NullPointerException
at de.myproject.project.classTest.testGetParameters(classTest.java:123)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
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:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:678)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)


Here is the written test:

public class classTest {

// class under test
private classUnderTest classUnderTest;

private LineConfigurationHandler LineConfigurationHandlerMock;

private IMocksControl mocksControl;

List<DeviceParameter> myDeviceParameters;
DeviceParameter deviceParameter1;
DeviceParameter deviceParameter2;

@Before
public void setUp() throws Exception
{
mocksControl = EasyMock.createControl();

LineConfigurationHandlerMock = mocksControl.createMock(LineConfigurationHandler.class);

classUnderTest = new classUnderTest();
classUnderTest.setLineConfigurationHandler(LineConfigurationHandlerMock);

String item1 = "item1";

myDeviceParameters = new ArrayList<DeviceParameter>();
myDeviceParameters.add(deviceParameter1);
myDeviceParameters.add(deviceParameter2);

//Other stuff
}

@Test
public void testGetParameters()
{

expect(LineConfigurationHandlerMock.getDeviceControlHandler().getDeviceParameters(item1)).andReturn(myDeviceParameters);

mocksControl.replay();

//Some code .....
}
}


Here is the class under test :

public Class ClassUnderTest
{
@Inject
private LineConfigurationHandler lineConfigurationHandler;

public List<DeviceParameter> getDeviceParameters(String deviceId)
{
// Method implementation
}

@Required
public void setLineConfigurationHandler(LineConfigurationHandler lineConfigurationHandler)
{
this.lineConfigurationHandler = lineConfigurationHandler;
}
}


The interface in which the method is declared

public interface LineConfigurationHandler {

DeviceControlHandler getDeviceControlHandler();

//other Method declaration ...
}


DeviceControlHandler.class

public interface DeviceControlHandler extends Serializable{

List<DeviceParameter> getDeviceParameters(String deviceId);

//Other methods declaration ...
}

Answer

It is not simple, but very deterministic:

expect(lineConfigurationHandlerMock.getDeviceControlHandler().getDeviceParameters(item1)).andReturn(myDeviceParameters);

That line contains two items that can throw NPE:

A) lineConfigurationHandlerMock --> that object can be NULL

B) .getDeviceControlHandler() --> that method can return NULL

That's it. You can do simple printouts, like

System.out.println("mock: " + lineConfigurationHandlerMock)
System.out.println("handler: " + lineConfigurationHandlerMock.getDeviceControlHandler())

to figure which one is null. In your case, I think you are missing the setup for your lineConfigurationHandlerMock object: you have to tell it what to return when getDeviceControlHandler() is called.

In order to do that, you first have to create another mock object that should be returned when getDeviceControlHandler() is called. And that other mock, you have to configure for a call to getDeviceParameters()!

In other words: you can't specify like "mock.getA().doSomething()" - instead, you need another "mockedA" which you tell "doSomething()"; and then you tell "mock" that getA() should return "mockedA".

Update: I am not familiar with these annotations; I am used to use "EasyMock in a bare metal mode"; like

SomeObject innerMock = EasyMock.createMock(SomeObject);
expect(innerMock.doSomething()).andReturn("who cares");

SomeOther outerMock = EasyMock.createMock(SomeOther);
expect(outerMock.getDeviceControlHandler("sounds familiar")).andReturn(innerMock);
Comments