Java – How to mock a method with generic objects in JMockit

genericsjavajmockitmocking

This question is self explanatory if you know how to use JMockit: How do I mock a method that has generics on it? I want to mock this method: public T save(T entity) but it always throws an exception like this:

mockit.RealMethodNotFoundForMockException: Corresponding real methods not found for the following mocks:
Object save(Object)
    at mockit.internal.RedefinitionEngine.modifyRealClass(RedefinitionEngine.java:130)
    at mockit.internal.RedefinitionEngine.modifyRealClass(RedefinitionEngine.java:88)
    at mockit.internal.RedefinitionEngine.redefineMethods(RedefinitionEngine.java:72)
    at mockit.Mockit.setUpMocks(Mockit.java:197)
    at com.mytest.MyTest.setUp(AdminManagerImplTest.java:83)

Best Solution

Just for the sake of completeness:

I had a similar issue with Java 1.7 in Java 1.6 mode, TestNG and jMockit 1.5 and 1.16, using in-method MockUp<...> of a class.

My class:

public class MyCache extends AbstractLazyCache<ExchangeObject> {...}

The mocked method:

 public abstract class AbstractLazyCache<CachedObject> extends AbstractCache {
      // ...

      protected void putCachedObject(String tenantId, String objectId, CachedObject o, Date expiryDate) {...}
  }

Original mocking attempt:

    new MockUp<MyCache>() {
        // invoked once manually, once on expired cache
        @Mock(invocations = 2)
        public void putCachedObject(Invocation inv, String tenantId, String objectId,
                RangeExchange o, Date expiryDate) {
            // expire one second in the future
            inv.proceed(tenantId, objectId, o, new Date(System.currentTimeMillis() + waitTimeMillis));
        }
    };

I got a similar exception. By adding an additional generic parameter after public, my test case finally succeeded:

    new MockUp<MyCache>() {
        // invoked once manually, once on expired cache
        @Mock(invocations = 2)
        public <RangeExchange> void putCachedObject(Invocation inv, String tenantId, String objectId,
                RangeExchange o, Date expiryDate) {
            // expire one second in the future
            inv.proceed(tenantId, objectId, o, new Date(System.currentTimeMillis() + waitTimeMillis));
        }

    };