JMockit 有没有办法从模拟方法调用原始方法?
在我的模拟类中,我正在模拟方法 foo()。 对于某些测试用例,我希望 foo() 的模拟实现返回一个特殊值。 对于其他测试用例,我想使用 foo() 的实际实现。 我在模拟类中定义了一个布尔值,以便我可以在模拟方法中确定是否要返回特殊值,还是使用“真实”方法。 问题是,我似乎无法弄清楚如何从模拟方法中调用真正的方法。
我发现您可以在名为“it”的模拟对象中定义一个特殊成员(具有被模拟对象的类型)。 这允许您从模拟实现中引用真实的类。 所以,我的计划是,如果我需要调用 foo() 的“真实”实现,模拟方法将调用 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:另外,对于我的大多数测试用例,我不想要模拟实现。 因此,我最初的尝试是仅在需要模拟对象的测试用例中调用 Mockit.redefineMethods() 。 但这不起作用 - 似乎你只能在安装/拆卸中执行此操作...当我尝试这样做时,我的模拟实现从未被调用。
解决方案的注释:
起初我认为给出的答案不起作用,但在玩了一些之后,问题似乎是我将 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();
}
}
}
In my mock class, I'm mocking method foo(). For some test cases, I want the mock implementation of foo() to return a special value. For other test cases, I want to use the real implementation of foo(). I have a boolean defined in my mock class so that I can determine in the mock method whether I want to return the special value, or use the "real" method. The problem is, I can't seem to figure out how to call the real method from the mocked method.
I found that you can define a special member within the mock object named "it" (with type of the object being mocked). This allows you to reference the real class from the mock implementation. So, my plan was, if I needed to invoke the "real" implementation of foo(), the mock method would call it.foo(). However, this doesn't work, because calling it.foo() just calls the mock version again, not the real version, so I end up with infinite recursion.
Is there some way to make this work?
EDIT: it might be clearer with a code example, here's what my current mocked method implementation looks like:
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();
}
}
EDIT 2: Also, for most of my test cases I do NOT want the mock implementation. So my initial attempt at this was to only call Mockit.redefineMethods() within those test cases where I needed the mock object. But this didn't work - it seems you can only do this within setup/teardown ... my mock implementation never got called when I tried that.
NOTES ON SOLUTION:
At first I didn't think the answer given worked, but after playing with it some more, it seems the problem is that I was mixing JMockit "core" methods with the "annotation" driven methods. Apparently when using the annotation you need to use Mockit.setupMocks, not Mockit.redefineMethods(). This is what finally worked:
@Before
public void setUp() throws Exception
{
Mockit.setUpMocks(MyMockClass.class);
}
Then, for the mock 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();
}
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
在 JMockit 的较新版本中,
可以从
实现。 请参阅访问调用上下文。中调用 Invocable.proceed()
MockUpIn more recent versions of JMockit,
Invocation.proceed()
can be called from within aMockUp
implementation. See Accessing the invocation context.我认为你可以使用
@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
不过我还没有测试过这个..
I think you can do this with the
@Mock
annotation. From the docs,@Mock(reentrant=true)
on your mock class should do it.See http://jmockit.googlecode.com/svn/trunk/www/javadoc/mockit/Mock.html
For an example look here http://jmockit.googlecode.com/svn/trunk/www/tutorial/StateBasedTesting.html#reentrant
I haven't tested this though..
您还可以对要测试的对象进行子类化并重写应返回特殊值的方法,而不是抛出模拟对象。
例如:
通过在测试中保留此定义,其他人也可以清楚哪些方法正在被“模拟”。
Instead of throwing in a mock object you could also subclass the object you want to test and override the methods that should return special values.
For example:
By keeping this definition within your test it is also clear for others which methods are being 'mocked'.
谁仍然感兴趣, Jmockit docs 中都有对此的支持
无论 以本题为例,可以这样实现:
Whomever is still interested, there is a support for that in Jmockit docs
So given this question as an example, it can be achieved as follows: