Java JMockit中有没有从模拟方法调用原始方法的方法?

Java JMockit中有没有从模拟方法调用原始方法的方法?,java,mocking,jmockit,Java,Mocking,Jmockit,在我的mock类中,我在模拟方法foo()。对于一些测试用例,我希望foo()的模拟实现返回一个特殊值。对于其他测试用例,我想使用foo()的实际实现。我在mock类中定义了一个布尔值,这样我就可以在mock方法中确定是返回特殊值,还是使用“real”方法。问题是,我似乎不知道如何从模拟方法调用真正的方法 我发现可以在mock对象中定义一个名为“it”的特殊成员(对象类型为mock)。这允许您从模拟实现中引用真实类。因此,我的计划是,如果需要调用foo()的“真实”实现,mock方法将调用它。f

在我的mock类中,我在模拟方法foo()。对于一些测试用例,我希望foo()的模拟实现返回一个特殊值。对于其他测试用例,我想使用foo()的实际实现。我在mock类中定义了一个布尔值,这样我就可以在mock方法中确定是返回特殊值,还是使用“real”方法。问题是,我似乎不知道如何从模拟方法调用真正的方法

我发现可以在mock对象中定义一个名为“it”的特殊成员(对象类型为mock)。这允许您从模拟实现中引用真实类。因此,我的计划是,如果需要调用foo()的“真实”实现,mock方法将调用它。foo()。但是,这不起作用,因为调用它.foo()只会再次调用模拟版本,而不是真正的版本,因此我最终使用无限递归

有什么办法可以让它工作吗

编辑:代码示例可能更清楚,下面是我当前的模拟方法实现的样子:

private RealClass it;
...
public SomeClass foo() {
    if(fakeIt) {
        return new SomeClass("fakevalue");
    } else {
        // doesn't work, just keeps calling the mock foo
        // in infinite recursion
        return it.foo();
    }
}
编辑2:另外,对于我的大多数测试用例,我不想要模拟实现。因此,我最初的尝试是仅在需要模拟对象的测试用例中调用Mockit.redefineMethods()。但这不起作用-似乎您只能在安装/拆卸中执行此操作。。。当我尝试这样做时,我的模拟实现从未被调用

解决方案说明:

起初我认为给出的答案不起作用,但在进一步研究之后,问题似乎是我将JMockit“核心”方法与“注释”驱动的方法混合在一起了。显然,在使用注释时,您需要使用Mockit.setupmock,而不是Mockit.redefineMethods()。这就是最终成功的原因:

@Before 
public void setUp() throws Exception
{
    Mockit.setUpMocks(MyMockClass.class);
}
然后,对于模拟类:

@MockClass(realClass = RealClass.class)
public static class MyMockClass {
    private static boolean fakeIt = false;
    private RealClass it;

    @Mock(reentrant = true)
    public SomeClass foo() {
        if(fakeIt) {
            return new SomeClass("fakevalue");
        } else {
            return it.foo();
        }
    }
}

除了抛出一个模拟对象,您还可以对要测试的对象进行子类化,并重写应该返回特殊值的方法

例如:

RealClass toTest = new RealClass(){
      public String foo(){
          return "special value";
      }
}

//use toTest in test

通过在您的测试中保留此定义,其他人也可以清楚地知道哪些方法正在被“模拟”。

我认为您可以通过
@Mock
注释来实现这一点。从文档中可以看出,Mock类上的
@Mock(reentrant=true)
应该可以做到这一点


例如,请看这里


不过我还没有测试过这一点。

在较新版本的JMockit中,可以从实现中调用。看

公共类MyMockClass扩展了实体模型{
私有静态布尔fakeIt=false;
@嘲弄
公共类foo(调用inv){
if(fakeIt){
返回新的SomeClass(“fakevalue”);
}否则{
返回库存继续();
}
}
}

谢谢你的建议!不幸的是,我不能使用这种方法,因为我正在模拟的类实际上不是由测试用例直接创建的。它是由正在测试的对象创建的。我一定是遗漏了什么。从文档上看,这听起来很有希望,但我使用reentrent=true还是false似乎并不重要,我得到的行为和以前一样。文档还说“默认情况下,这样的调用是不允许的,因为它们会导致无限递归…”所以我很困惑。在进一步检查后,我发现了我缺少的东西:)我更新了JavaDoc链接并添加了一个示例链接+答案是1。链接已经断开,因为它已经超过6年了。我认为值得注意的是,这个答案只有在问题被回答时才有效。此后,在JMockit的最新版本中,JMockit API中就不推荐使用这种方法。Trevor Robinson给出的答案现在是最好的答案,依我看。这个答案只有在你使用JMockit的旧版本时才仍然有效。这个答案中的链接是一个断开的链接。JMockIt的新链接:()
public class MyMockClass extends MockUp<RealClass> {

    private static boolean fakeIt = false;

    @Mock
    public SomeClass foo(Invocation inv) {
        if (fakeIt) {
            return new SomeClass("fakevalue");
        } else {
            return inv.proceed();
        }
    }
}