4

如果您知道如何使用 JMockit,这个问题是不言自明的:如何模拟具有泛型的方法?我想模拟这个方法: public T save(T entity) 但它总是抛出这样的异常:

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)
4

4 回答 4

2

只是为了完整起见:

我在 Java 1.6 模式、TestNG 和 jMockit 1.5 和 1.16 中使用类的方法内 MockUp<...> 时遇到了类似的问题。

我的课:

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

模拟方法:

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

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

原始模拟尝试:

    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));
        }
    };

我有一个类似的例外。通过在 public 之后添加一个额外的泛型参数,我的测试用例终于成功了:

    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));
        }

    };
于 2015-03-17T16:00:57.090 回答
1

它对我有用,例如

包一个;

导入 junit.framework.TestCase;
导入 mockit.Mockit;

公共类 JMockitCoreExampleTest 扩展 TestCase {

    公共类 MockMe {
        公共T保存(T t){
            返回空值;
        }
    }

    公共无效 testDoOperationAbc() {
        Mockit.redefineMethods(MockMe.class, SayThatYouMockMe.class);
                MockMe 模拟 = 新的 MockMe();
        System.out.println(mock.save("aaa"));
    }

    公共静态类 SayThatYouMockMe {
        公共T保存(T t){
            返回 t;
        }
    }
}

输出

加载的外部工具:mockit.integration.junit3.JUnitTestCaseDecorator
加载的外部工具:mockit.integration.junit4.JUnit4ClassRunnerDecorator
啊啊啊

也许你在嘲笑hibernate的保存方法?如果是这样,请尝试使用 jmockit 的 hibernate3emul.jar

于 2009-02-02T19:41:10.883 回答
0

我认为您的问题可能是您的泛型类型签名与您尝试模拟的方法不匹配。请记住,泛型类型信息在运行时不可用,因此 JMockit 只能看到擦除泛型类型信息所产生的方法。

例如,假设您有以下签名:

public <T> void foo(T param) {
  ...
}

编译器将其转换为:

public void foo(Object param) {
  ...
}

这是出现在字节码中的签名,也是 JMockit 通过反射看到的。

相比之下,以下签名:

public <T extends Map> foo(T param) {
  ...
}

擦除到:

public void foo(Map param) {
  ...
}

因此,例如,如果您的模拟实现使用第一个签名,而实际类使用第二个签名,则底层擦除将不匹配,并且 JMockit 将无法找到该方法。

有关更多信息,请参见http://today.java.net/pub/a/today/2003/12/02/explorations.html

于 2009-02-02T21:04:45.440 回答
0

也许你和我有同样的星座:

我尝试模拟方法<T> T merge(T t)org.hibernate.ejb.EntityManagerImpl得到相同的 Mockit 错误。

Mockit.redefineMethods(EntityManagerImpl.class, EntityManagerImplMock.class);

我的错是合并方法不是在它的超类中声明的,org.hibernate.ejb.EntityManagerImpl而是在它的超类中声明的AbstractEntityManagerImpl。我现在有

Mockit.redefineMethods(AbstractEntityManagerImpl.class, EntityManagerImplMock.class);

public static class EntityManagerImplMock {
    public <T> T merge(final T o) {
        // nothing
        return o;
    }
}

一切正常。

于 2009-10-28T13:40:54.213 回答