有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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) 个答案

  1. # 1 楼答案

    隐藏类(静态)方法与重写实例方法的效果不太一样。要证明JMock不是罪魁祸首,请尝试以下方法:

    public class test3 {
    public static void main(String[] args) {
        Owner owner = new Owner();
        owner.getThing().method(); //Like how you execute your test
        RealThing thing = new RealThing();
        thing.method(); //Similar to your mock.
    }
    
    private static class Owner {
        private BaseThing thing = new RealThing();
    
        public BaseThing getThing() {
            return thing;
        }
    }
    
    private static class BaseThing {
        public static void method() {
            System.out.println("Basething!");
        }
    }
    
    private static class RealThing extends BaseThing {
        public static void method() {
            System.out.println("Realthing!");
        }
    }
    }
    

    请注意,对method()的两个调用打印不同的内容!两者都是RealThing的实例,但它们调用不同的方法。调用的静态方法取决于它是从子类调用还是从超类调用。在上面的第一个调用中,方法被声明为基类,因此BaseClass.method()被调用,即使它是RealClass的实例。对method()的第二个调用被声明为RealClass,因此RealClass.method()被调用

    因此,JMock的结果是有效的。调用的method()与您为其设置的期望值不同

    对我的解释不太满意。请在这里仔细阅读:http://docs.oracle.com/javase/tutorial/java/IandI/override.html


    修复(有利于BaseThing.method()),更改:

    final RealThing thing = mockery.mock(RealThing.class, "thing");
    

    致:

    final BaseThing thing = mockery.mock(RealThing.class, "thing");
    

    或者,如果您更喜欢使用RealThing.method(),请更改:

    owner.getThing().method()
    

    致:

    RealThing thing = (RealThing)owner.getThing();
    thing.method();