Search code examples
javajunitmockingeasymock

EasyMock capture throws NullPointerException


I suddenly stumbled upon an issue that I need to capture a parameter of this interface called:

public interface MyInterface {

    void doSomething(long id);
}
@Mock
private MyInterface myInterface;

...

Capture<Long> capturedId = Capture.newInstance();
myInterface.doSomething(capture(capturedId));

The test failed quite early:

java.lang.NullPointerException
  at com.mycompany.MyInterfaceTest.doSomethingTest(MyInterfaceTest.java:81)
  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)

I triple-checked that no way a null is passed, what is going on?


Solution

  • The issue is the implementation of the EasyMock#capture(Capture<T>) method that always returns null:

    public static <T> T capture(final Capture<T> captured) {
        reportMatcher(new Captures<T>(captured));
        return null;
    }
    

    This would not be a problem if the mocked method would accept an object type Long as a parameter:

    void doSomething(long id);
    

    ... however, the long primitive type is present and the attempt of unboxing the return value (null) of the EasyMock#capture(Capture<T>) method fails on NullPointerException.

    The fix is simple: For this reason, there were introduced method variations suitable for primitive types, such as EasyMock#captureLong(Capture<Long>):

    myInterface.doSomething(captureLong(capturedId));