Easymock: имеет ли значение порядок снимков? - PullRequest
6 голосов
/ 19 февраля 2009

Это может показаться довольно подробным вопросом о Easymock, но мне трудно найти сайт поддержки / форум / список рассылки для этой библиотеки.

Я сталкиваюсь с ошибкой при использовании метода captures(), который, кажется, возвращает захваченные параметры не по порядку.

Вот упрощенная версия того, что я тестирую:

public class CaptureTest extends TestCase {

    // interface we will be mocking
    interface Processor {
            void process(String x);
    }

    // class that uses the interface above which will receive the mock
    class Component {

        private Processor processor;

        private String[] s = { "one", "two", "three", "four" };

        Component(Processor processor) {
            this.processor = processor;
        }

        public void doSomething() {
            for (int i = 0; i < s.length; i++) {
                processor.process(s[i]);
            }
        }
}

    public void testCapture() {

        //create the mock, wire it up    
        Processor mockProcessor = createMock(Processor.class);
        Component component = new Component(mockProcessor);

        //we're going to call the process method four times
        //with different arguments, and we want to capture 
        //the value passed to the mock so we can assert against it later    
        Capture<String> cap1 = new Capture<String>();
        Capture<String> cap2 = new Capture<String>();
        Capture<String> cap3 = new Capture<String>();
        Capture<String> cap4 = new Capture<String>();

        mockProcessor.process(and(isA(String.class), capture(cap1)));
        mockProcessor.process(and(isA(String.class), capture(cap2)));
        mockProcessor.process(and(isA(String.class), capture(cap3)));
        mockProcessor.process(and(isA(String.class), capture(cap4)));

        replay(mockProcessor);

        component.doSomething();

        //check what values were passed to the mock
        assertEquals("one", cap1.getValue());
        assertEquals("two", cap2.getValue());
        assertEquals("three", cap3.getValue());
        assertEquals("four", cap4.getValue());

        verify(mockProcessor);
    }

}

(Обратите внимание, что это всего лишь упрощенный тестовый пример - я знаю, что могу указать точное значение аргументов, которые я ожидаю передать моему макету, но в моем реальном случае аргументы - это сложные объекты с несколькими полями, и я хочу захватить объект, чтобы можно было утверждать только некоторые из этих полей, не создавая заново весь объект в моем тестовом примере).

Когда я запускаю тест, он терпит неудачу в:

junit.framework.ComparisonFailure: ожидается: <[one]>, но было: <[four]>

Это означает, что параметр, который EasyMock записывает в cap1, является не первым вызовом метода, а последним (поскольку значение four). Я получаю те же результаты, если перевернуть декларации captures(), т. Е. Использовать cap4 с первым вызовом метода и т. Д.

Похоже, что это может быть ошибкой в ​​EasyMock - разные параметры, переданные одному и тому же методу в разных вызовах, похоже, не фиксируются правильно.

Кто-нибудь еще использует capture() с EasyMock и имеет подобные проблемы? Есть ли простой обходной путь, о котором вы знаете, или другой способ, которым я могу зафиксировать параметры, передаваемые методам моего макета?

Обновление 1 : исправлен пример кода, показывающий, что я использую createMock, а не createStrictMock, но я получаю одинаковую ошибку с обоими (хотя фактическое значение того, что записано, меняется).

Ответы [ 6 ]

4 голосов
/ 20 февраля 2009

Я получил ответ на ошибку, которую я отправил на сайт sourcemoge Easymock, и разработчик подтвердил, что это действительно ошибка в этой версии Easymock.

Это действительно ошибка. Захват сделан, даже если это уже было сделано. Текущий обходной путь - реализовать собственный объект захвата и переопределить setValue для этого:

@Override
public void setValue(T value) {
  if(!hasCaptured()) {
    super.setValue(value);
  }
}
1 голос
/ 19 февраля 2009

Я играл с вашим тестом и не мог решить. Однако я расширил класс Capture, чтобы увидеть, были ли значения установлены в другом порядке (я подозревал, что EasyMock внутренне использовал хэш с ключом, сгенерированным из методов и параметров). Я ошибся, методы установлены в правильном порядке. , Но происходит что-то действительно странное ... Кажется, что алгоритм выполняет какой-то шаблон назначения ... Хорошо, позвольте мне показать код и странный вывод .... Кстати, изменения из mock, niceMock и strictMock не сделали различий ..

class MyCapture extends Capture<String> {

    private String id;

    public MyCapture(String id) {
        super();
        System.out.printf("Constructor %s expecting %s\n", id, this.getClass().getName());
        this.id = id;
    }

    private static final long serialVersionUID = 1540983654657997692L;

    @Override
    public void setValue(String value) {
        System.out.printf("setting value %s expecting %s \n", value, id);
        super.setValue(value);
    }

    @Override
    public String getValue() {
        System.out
                .printf("getting value %s expecting %s \n", super.getValue(), id);
        return super.getValue();
    }
}


public void testCapture() {

    // create the mock, wire it up
    Processor mockProcessor = createStrictMock(Processor.class);
    Component component = new Component(mockProcessor);

    // we're going to call the process method four times
    // with different arguments, and we want to capture
    // the value passed to the mock so we can assert against it later
    Capture<String> cap1 = new MyCapture("A");
    Capture<String> cap2 = new MyCapture("B");
    Capture<String> cap3 = new MyCapture("C");
    Capture<String> cap4 = new MyCapture("D");

    mockProcessor.process(and(isA(String.class), capture(cap1)));
    mockProcessor.process(and(isA(String.class), capture(cap2)));
    mockProcessor.process(and(isA(String.class), capture(cap3)));
    mockProcessor.process(and(isA(String.class), capture(cap4)));
    replay(mockProcessor);

    component.doSomething();

    // check what values were passed to the mock
    assertEquals("A", cap1.getValue());
    assertEquals("B", cap2.getValue());
    assertEquals("C", cap3.getValue());
    assertEquals("D", cap4.getValue());

    verify(mockProcessor);
}

}

* И это выход *

Constructor A expecting com.comp.core.dao.impl.CaptureTest$MyCapture
    Constructor B expecting com.comp.core.dao.impl.CaptureTest$MyCapture
    Constructor C expecting com.comp.core.dao.impl.CaptureTest$MyCapture
    Constructor D expecting com.comp.core.dao.impl.CaptureTest$MyCapture
    calling process A 
    setting value A expecting A 
    calling process B 
    setting value B expecting A <<Setting the wrong guy
    setting value B expecting A <<Setting the wrong guy
    setting value B expecting B <<Ops this is the right one..stop
    calling process C 
    setting value C expecting B <<Setting the wrong guy
    setting value C expecting B <<Setting the wrong guy
    setting value C expecting C <<Setting the wrong guy
    calling process D 
    setting value D expecting C <<Setting the wrong guy
    setting value D expecting C <<Setting the wrong guy
    setting value D expecting D <<Ops this is the right one..stop
    getting value B expecting A 

Извините, я не могу вам больше помочь. Это может быть действительно ошибка в легком издевательстве.

0 голосов
/ 20 февраля 2015

Короче, вот что у меня сработало:

MyClass myMock = EasyMock.createStrictMock(MyClass.class);

...

EasyMock.checkOrder(myMock, true); // before the capture and verify, not sure if it matters

...

Capture<MyArg> capturedArgs = new Capture<MyArg>();
expect(myMock.search(capture(capturedArgs))).andReturn(someRandomReturn);

PS: я использую EasyMock 3.0

0 голосов
/ 29 июня 2009

Я думаю, что эта проблема больше подходит для тестирования на основе состояния. С JMockit вы можете решить это так:

import mockit.*;
import static mockit.Mockit.*;
import mockit.integration.junit3.*;

public class CaptureTest extends JMockitTestCase
{
   interface Processor { void process(String x); }

   class Component
   {
      private final Processor processor;
      private final String[] s = {"one", "two", "three", "four"};

      Component(Processor processor) { this.processor = processor; }

      public void doSomething()
      {
         for (String value : s) {
            processor.process(value);
         }
      }
   }

   @MockClass(realClass = Processor.class)
   static class MockProcessor
   {
      private final String[] expectedValues;
      private int i;

      MockProcessor(String... expectedValues) { this.expectedValues = expectedValues; }

      @Mock
      void process(String x)
      {
         assertEquals(expectedValues[i++], x);
      }
   }

   public void testCapture()
   {
      Processor mockProcessor = setUpMock(new MockProcessor("one", "two", "three", "four"));
      Component component = new Component(mockProcessor);

      component.doSomething();
   }
}
0 голосов
/ 19 февраля 2009

Вы также можете попробовать использовать EasyMock.createNiceMock (...) вместо EasyMock.createStrictMock (...) или EasyMock.createMock (...).

Хотя я согласен, что это больше похоже на ошибку в createMock.

0 голосов
/ 19 февраля 2009

Вместо вызова EasyMock.createStrictMock (...) просто вызовите EasyMock.createMock (...) . Должны решить ваши проблемы.

...