在我的模拟课中,我正在模拟方法foo()。对于某些测试用例,我希望foo()的模拟实现返回一个特殊值。对于其他测试用例,我想使用foo()的实际实现。我在我的mock类中定义了一个布尔值,以便我可以在mock方法中确定是否要返回特殊值,或使用“real”方法。问题是,我似乎无法弄清楚如何从模拟方法中调用真实方法。
我发现你可以在名为“it”的模拟对象中定义一个特殊成员(具有被模拟对象的类型)。这允许您从模拟实现中引用真实类。所以,我的计划是,如果我需要调用foo()的“真正”实现,mock方法将调用it.foo()。但是,这不起作用,因为调用it.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:另外,对于我的大多数测试用例,我 NOT 想要模拟实现。所以我最初的尝试是在我需要模拟对象的那些测试用例中只调用Mockit.redefineMethods()。但这不起作用 - 看起来你只能在setup / teardown中这样做...我的模拟实现从未在我尝试时被调用。
解决方案说明:
起初我并不认为给出的答案有效,但在使用它之后,似乎问题在于我将JMockit“核心”方法与“注释”驱动方法混合在一起。显然,在使用注释时,您需要使用Mockit.setupMocks,而不是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();
}
}
}
答案 0 :(得分:7)
我认为您可以使用@Mock
注释执行此操作。从文档中,模拟类的@Mock(reentrant=true)
应该这样做。
参见http://jmockit.googlecode.com/svn/trunk/www/javadoc/mockit/Mock.html
有关示例,请查看http://jmockit.googlecode.com/svn/trunk/www/tutorial/StateBasedTesting.html#reentrant
我没有测试过这个..
答案 1 :(得分:6)
在更新版本的JMockit中,Invocation.proceed()
可以在MockUp
实现中调用。请参阅Faking: Proceeding into the real implementation。
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();
}
}
}
答案 2 :(得分:1)
您可以将要测试的对象子类化,并覆盖应返回特殊值的方法,而不是抛出模拟对象。
例如:
RealClass toTest = new RealClass(){
public String foo(){
return "special value";
}
}
//use toTest in test
通过将此定义保留在您的测试中,其他人也清楚哪些方法被“嘲笑”。