java - 为什么 JMockIt 在这段代码中模拟 X 类的 getter X.getE() ?

标签 java enums getter jmockit

注意:问题末尾附有完整工作的代码片段

我有一个类的 JMockIt 测试 Service有两个依赖项(代码片段中的 FactoryConsumer)。该服务内部询问 FactoryX 的对象的依赖关系,然后将该对象传递给 Consumer该方法的依赖关系:

public void interact(int i, E e) { X v = f.create(i, e); c.consume(v); }

在我的测试中,我想练习 Service.interact()方法并通过严格的期望假设消费者应收到满足特定属性的参数值。现在,由于类型 X 的参数是一个没有实现 equals() 的 POJO,我想使用它提供的 getter 方法来执行我的检查; X看起来像这样(完整的代码片段在问题末尾):

public static class X { private final int i; public final E e; // ... see below for full snippet public int getI() { return i; } public E getE() { return e; } // E is an enum

所以我所做的就是尝试检查消费者是否收到 X.getI() == 2 的值和X.getE() == E.B我使用with(Delegate<X>)来做到这一点和withArgThat(Matcher<X>)在我的期望 block 中:

new StrictExpectations() {{ consumer.consume(withArgThat(new BaseMatcher() { // ... // and new StrictExpectations() {{ consumer.consume(with(new Delegate() { // ...

但是,这两项检查都失败了,因为当它们调用 X.getE() 时他们收到的东西不是枚举值 E.B 。单元测试的输出为:

-----------------------------------------
RUNNING CHECKS ON: i=2, e=B
Direct reference match.
Reference through getter mismatch!
Ordinal through getter reference: 0
Identity hashcode from getter reference: 1282788025
Identity hashcode of expected reference: 519569038
-----------------------------------------
RUNNING CHECKS ON: i=2, e=B
Direct reference match.
Reference through getter mismatch!
Ordinal through getter reference: 0
Identity hashcode from getter reference: 1911728085
Identity hashcode of expected reference: 519569038

第一个问题是(这篇文章的标题):为什么 JMockIt 首先要干预这个 getter?据我所知,我没有要求它模拟类 X,因此对其 getter 方法的调用应该进入常规 X 字节码,但显然它没有;返回的枚举值的序数为零,这似乎是模拟的默认值。这是预期的行为,因为我错过/误解了某些东西,或者它可能是一个错误?

第二个问题是:假设 JMockIt 的行为有正当理由,我怎样才能实现我想要的并对只能通过 X 的 getter 方法获取的值执行这种检查?我如何修复此代码以告诉 JMockIt 只需离开类 X独自一人。

这是将编译和运行的完整代码片段(也在 http://pastebin.com/YRL7Pdzv ),我的类路径中有 junit-4.12、hamcrest-core-1.3 和 jmockit-1.14,并使用 Oracle JDK 1.7.0_51。

package demonstrate;

import mockit.Delegate;
import mockit.Mocked;
import mockit.NonStrictExpectations;
import mockit.StrictExpectations;

import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
import org.junit.Before;
import org.junit.Test;

public class SomeTest {
    @Mocked
    Factory factory;
    @Mocked
    Consumer consumer;

    @Before
    public void setUp() {
        new NonStrictExpectations() {{
            factory.create(anyInt, (E) any);
            result = new Delegate() {
                @SuppressWarnings("unused")
                public X create(int i, E e) {
                    return new X(i, e);
                }
            };
        }};
    }

    @Test
    public void testWithMatcher() {
        System.err.println("-----------------------------------------");
        new StrictExpectations() {{
            consumer.consume(withArgThat(new BaseMatcher() {
                final int i = 2; final E e = E.B;
                @Override
                public boolean matches(Object item) {
                    return runChecks((X) item, i, e);
                }
                @Override
                public void describeTo(Description description) {
                    description.appendText("\"i=" + i + ", e=" + e.name() + "\"");
                }
            }));
        }};
        new Service(factory, consumer).interact(2, E.B);
    }

    @Test
    public void testWithDelegate() {
        System.err.println("-----------------------------------------");
        new StrictExpectations() {{
            consumer.consume(with(new Delegate() {
                @SuppressWarnings("unused")
                public boolean check(X x) {
                    return runChecks(x, 2, E.B);
                }
            }));
        }};
        new Service(factory, consumer).interact(2, E.B);
    }

    private static boolean runChecks(X actual, int i, E e) {
        System.err.println("RUNNING CHECKS ON: " + actual);
        if (actual.getI() != i) {
            System.err.println("Primitive int mismatch!");
            return false;
        }
        if (actual.e == e) {
            System.err.println("Direct reference match.");
        } else {
            System.err.println("Reference mismatch!");
            return false;
        }
        E otherE = actual.getE();
        if (otherE != e) {
            System.err.println("Reference through getter mismatch!");
            System.err.println("Ordinal through getter reference: "
                    + otherE.ordinal());
            System.err.println("Identity hashcode from getter reference: "
                    + System.identityHashCode(otherE));
            System.err.println("Identity hashcode of expected reference: "
                    + System.identityHashCode(e));
            return false;
        }
        return true;
    }

    public enum E {
        A, B
    }

    public static class X {
        private final int i;
        public final E e;

        public X(int i, E e) {
            this.i = i;
            this.e = e;
        }

        @Override
        public String toString() {
            return "i=" + i + ", e=" + e.name();
        }

        public int getI() {
            return i;
        }

        public E getE() {
            return e;
        }
    }

    public static class Factory {
        public X create(int i, E e) {
            return new X(i, e);
        }
    }

    public static class Consumer {
        public void consume(X arg) {
        }
    }

    public static class Service {
        private final Factory f;
        private final Consumer c;

        public Service(Factory f, Consumer c) {
            super();
            this.f = f;
            this.c = c;
        }

        public void interact(int i, E e) {
            X v = f.create(i, e);
            c.consume(v);
        }
    }
}

最佳答案

我在 jmockit-users 列表中被告知这实际上是一个错误。

建议的解决方法是使用 @Mocked(cascading = false) Factory 工厂; ,它确实使事情正常工作。

关于java - 为什么 JMockIt 在这段代码中模拟 X 类的 getter X.getE() ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27731395/

相关文章:

java - 根据元素字段对 ArrayList 进行排序

java - ParseEnum(方法)无法从 SuperCSV (Java) 中的 .csv 文件解析/读取字符串作为枚举

wpf 将组合框绑定(bind)到不同命名空间中的枚举

c# - 如何将大型标志枚举存储到 SQL 数据库中的单个列?

java - 即使我知道我永远不会需要它,在我的对象中包含一个 setter 是一个好习惯吗?

javascript - 从数字文字访问 "getter"的属性时,IE9 中出现奇怪的 `Number.prototype` 行为

java - JSF2.0 在托管 bean 之间传递值对象

java - Hibernate hql 内连接

java - actionPerformed() 在调整 JFrame 大小后执行多次

angular - 重复声明 TypeScript Getter Setter