Использование JMock2 с сопоставителями в Groovy: проблемы с методом with

У меня есть следующий фрагмент с ожиданиями JMock в моем методе тестирования:

context.checking(new Expectations() {{
    allowing(listener).tableChanged(with(anyInsertionEvent()));
    oneOf(listener).tableChanged(with(aRowChangedEvent(0)));
}});

где anyInsertionEvent и aRowChangedEventAs возвращают экземпляры Matcher<TableModelEvent>. Это взято из книги «Рост объектно-ориентированного программного обеспечения с помощью тестов» (стр. 181).

Я пытаюсь преобразовать этот тест в Groovy, но мне нужен метод:

org.jmock.Expectations.with(org.hamcrest.Matcher<T>)

затеняется:

org.codehaus.groovy.runtime.DefaultGroovyMethods.with(java.lang.Object, 
    groovy.lang.Closure<T>)

В результате во время тестов я получаю сообщение об ошибке:

groovy.lang.MissingMethodException: No signature of method: $Proxy8.tableChanged() is     applicable for argument types: (java.lang.Boolean) values: [false]
Possible solutions: tableChanged(javax.swing.event.TableModelEvent)
    at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:55)
    at org.codehaus.groovy.runtime.callsite.PojoMetaClassSite.call(PojoMetaClassSite.java:46)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
    at org.rorick.auctionsniper.ui.SnipersTableModelTest$1.<init>(SnipersTableModelTest.groovy:43)
    at org.rorick.auctionsniper.ui.SnipersTableModelTest.setSniperValuesInColumns(SnipersTableModelTest.groovy:42)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:66)
    at org.jmock.integration.junit4.JMock$1.invoke(JMock.java:37)
    at org.junit.internal.runners.MethodRoadie.runTestMethod(MethodRoadie.java:105)
    at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:86)
    at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:94)
    at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:84)
    at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:49)
    at org.junit.internal.runners.JUnit4ClassRunner.invokeTestMethod(JUnit4ClassRunner.java:98)
    at org.junit.internal.runners.JUnit4ClassRunner.runMethods(JUnit4ClassRunner.java:61)
    at org.junit.internal.runners.JUnit4ClassRunner$1.run(JUnit4ClassRunner.java:54)
    at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:34)
    at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:44)
    at org.junit.internal.runners.JUnit4ClassRunner.run(JUnit4ClassRunner.java:52)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:157)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:76)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:195)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:63)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)

Как я могу использовать подходящий with метод? Или, пожалуйста, посоветуйте другой способ решения этой проблемы.

ОБНОВЛЕНИЕ: не затенение. Фактически вызываемый метод - Expectations.with(Matcher<Boolean>), следовательно, false значение в трассировке стека. Итак, метод отправлен неправильно. Есть идеи, что с этим делать?

ОБНОВЛЕНИЕ: методы сопоставления следующие:

public Matcher<TableModelEvent> anyInsertionEvent() {
    Matcher<Integer> insertMatcher = equalTo(TableModelEvent.INSERT);
    return new FeatureMatcher<TableModelEvent, Integer>(insertMatcher, "is an insertion event", "event type") {
        @Override
        protected Integer featureValueOf(TableModelEvent actual) {
            return actual.getType();
        }
    };
}

private Matcher<TableModelEvent> aRowChangedEvent(int row) {
    return samePropertyValuesAs(new TableModelEvent(model, row));
}

person Rorick    schedule 04.09.2012    source источник
comment
Я не уверен, что вы правильно интерпретируете свое сообщение об ошибке. Вы говорите, что затенение метода вызывает проблему, но сообщение об ошибке, похоже, жалуется на тип, возвращаемый сопоставителем. Можете ли вы опубликовать полное сообщение об ошибке?   -  person Duncan Jones    schedule 05.09.2012
comment
Может, это не слежка. Но это полное сообщение об ошибке из журнала maven. И именно этот код отлично работает под Java, я просто переименовал файл. Итак, я полагаю, что с типами все в порядке: Expectations.with принимает Matcher<T> и возвращает T; anyInsertionEvent возвращает Matcher<TableModelEvent> и tableChanged ожидает TableModelEvent. Я посмотрю, смогу ли я рассказать поподробнее позже. Сейчас у меня нет доступа к этому коду.   -  person Rorick    schedule 05.09.2012
comment
Можем ли мы увидеть определения anyInsertionEvent и aRowChangedEventAs и ту часть теста, которая действительно вызывает ожидания? Кроме того, работало ли это когда-нибудь на чистой Java?   -  person Duncan Jones    schedule 06.09.2012
comment
Смотрите обновление. Да, он отлично работает, просто переименовав файл в java.   -  person Rorick    schedule 06.09.2012
comment
Итак, похоже, что Groovy просто не может отличить with(Matcher<T>) от with(Matcher<Boolean>) от with(Matcher) и т. Д.   -  person Rorick    schedule 06.09.2012
comment
Я полагаю, что чистая Java была бы тем же самым - стирание типа - хитрый дьявол. Это теперь решено в твоих глазах?   -  person Duncan Jones    schedule 06.09.2012
comment
Как я уже сказал, чистая Java легко различает эти методы, и тест Java проходит успешно. Groovy, похоже, стирает обобщенные шаблоны еще до компиляции, как указано в groovy.codehaus.org/Generics, поэтому у него нет шанс различить их. Я нашел способ обходного пути, хотя меня попросили заменить with самодельным argThat.   -  person Rorick    schedule 06.09.2012
comment
На данный момент борюсь с книгой, используя только Java (хотя и с AssertJ и Mockito, а не с Hamcrest и jMock). Ваш aRowChangedEvent выше, похоже, не выполняет то, что просит книга ... т.е. проверяет ровно одно вхождение события изменения строки. Вместо этого, похоже, указано количество всех TableModelEvents. Есть предложения, как реализовать это на Java (при условии, что вы взломали это на Java)?   -  person mike rodent    schedule 11.10.2016


Ответы (1)


Наконец, я нашел обходной путь для этого. См. Проверочный код ниже. new Expectations() {{}} Синтаксис Java исчез и заменен закрытием:

context.checking {
    allowing(listener).tableChanged(argThat(anyInsertionEvent()));
    oneOf(listener).tableChanged(argThat(aRowChangedEvent(0)));
}

Обратите внимание, что with заменяется на argThat (по образцу Mockito). context не является экземпляром как бы org.jmock.integration.junit4.JUnit4Mockery, а является экземпляром следующего класса:

class JUnit4GroovyMockery extends JUnit4Mockery {
    public void checking(Closure c) {
         ClosureExpectations expectations = new ClosureExpectations();
         expectations.closureInit(c, expectations);
         super.checking(expectations);
    }

    private static class ClosureExpectations extends Expectations {
        void closureInit(Closure cl, Object delegate) {
            cl.setDelegate(delegate);
            cl.call();
        }

        public Object argThat(Matcher<?> matcher) {
            currentBuilder().addParameterMatcher(matcher);
            return null;
        }
    }
}

Это основано на классе JUnit4GroovyMockery из http://docs.codehaus.org/display/GROOVY/Using+JMock+with+Groovy. argThat скопирован из Expectations.with(Matcher<T>) и Expectations.addParameterMatcher(Matcher<?>).

У меня это работает, хотя я не очень доволен этим решением; и я бы предпочел оставить with имя для метода.

person Rorick    schedule 05.09.2012