Почему JMockIt высмеивает метод получения X.getE () для класса X в этом фрагменте?

1

ПРИМЕЧАНИЕ. Полностью рабочий фрагмент кода следует в конце вопроса

У меня есть тест JMockIt для Service класса с двумя зависимостями (Factory и Consumer во фрагменте). Служба внутренне запрашивает зависимость Factory от объекта класса X, а затем доставляет этот объект зависимости от Consumer в этом методе:

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

В своем тесте я хочу использовать метод Service.interact() и постулировать с помощью строгого ожидания, что потребитель получит значение параметра, которое удовлетворяет определенным свойствам. Теперь, поскольку параметр типа X является POJO, который не реализует equals(), я хочу использовать его предоставленные методы 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() == EB и я делаю это, используя как with(Delegate<X>) и withArgThat(Matcher<X>) в моем ожидании:

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

Однако обе проверки не срабатывают, потому что, когда они вызывают X.getE() они получают то, что НЕ является значением перечисления EB. Выходной сигнал модульного теста:

-----------------------------------------
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 вмешивается в этот геттер в первую очередь? Насколько я могу судить, я не просил его издеваться над классом X, поэтому призывы к его методам getter должны входить в обычный X-образный 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);
        }
    }
}
Теги:
enums
getter
jmockit

1 ответ

1
Лучший ответ

Мне сказали в списке jmockit-users, что это на самом деле ошибка.

Рекомендуемым @Mocked(cascading = false) Factory factory; было использование @Mocked(cascading = false) Factory factory; и действительно, это заставляет вещи работать.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню