java JMock“意外调用”,当同一调用“预期一次,从未调用”
我在代码中的某个地方更改了一些方法,这些方法不应该导致任何奇怪的测试失败,但JMock似乎不这么认为
我把问题归结为最低限度的原油,看起来像这样:
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.jmock.Expectations;
import org.jmock.Mockery;
import org.jmock.lib.legacy.ClassImposteriser;
import org.junit.Test;
public class TestMocking {
@Test
public void test() {
Mockery mockery = new Mockery() {{
setImposteriser(ClassImposteriser.INSTANCE);
}};
final Owner owner = mockery.mock(Owner.class);
final RealThing thing = mockery.mock(RealThing.class, "thing");
mockery.checking(new Expectations() {{
oneOf(owner).getThing(); will(returnValue(thing));
oneOf(thing).method(); will(returnValue(Collections.emptyList()));
}});
owner.getThing().method();
mockery.assertIsSatisfied();
}
public static interface Owner {
BaseThing getThing();
}
public static interface BaseThing {
Collection<?> method();
}
public static interface RealThing extends BaseThing {
List<?> method();
}
}
(Edit:现在使用ClassImposteriser,即使已经没有类了,因为我想证明,您可以在没有冒名顶替器的情况下运行完全相同的代码,并且测试将通过。)
运行此命令的结果是:
unexpected invocation: thing.method()
expectations:
expected once, already invoked 1 time: owner.getThing(); returns <thing>
expected once, never invoked: thing.method(); returns <[]>
what happened before this:
owner.getThing()
这就是“意想不到”的事情。方法()时,将显示所需的内容。方法()从未被调用。我以前见过在多线程类对模拟对象进行测试时发生这种情况,但这次它都发生在单个线程中。这就像JMock在某种程度上返回了与第一个方法调用不同的模拟对象,尽管我没有模拟这样的对象
如果我删除了返回更具体类型的重写方法,那么它就会消失,但我显然不能这样做。类似地,如果我删除ClassImposteriser的使用,问题就会消失,但我在实际测试中模拟的对象之一是其他人的类。我想我可以试着在一个测试中使用两个嘲弄的例子,但除此之外,我没有想法
# 1 楼答案
隐藏类(静态)方法与重写实例方法的效果不太一样。要证明JMock不是罪魁祸首,请尝试以下方法:
请注意,对
method()
的两个调用打印不同的内容!两者都是RealThing的实例,但它们调用不同的方法。调用的静态方法取决于它是从子类调用还是从超类调用。在上面的第一个调用中,方法被声明为基类,因此BaseClass.method()
被调用,即使它是RealClass的实例。对method()
的第二个调用被声明为RealClass,因此RealClass.method()
被调用因此,JMock的结果是有效的。调用的
method()
与您为其设置的期望值不同对我的解释不太满意。请在这里仔细阅读:http://docs.oracle.com/javase/tutorial/java/IandI/override.html
修复(有利于
BaseThing.method()
),更改:致:
或者,如果您更喜欢使用
RealThing.method()
,请更改:致: