6

这似乎是一个关于 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,但两者都出现相同的错误(尽管捕获的实际值发生了变化)。

4

6 回答 6

4

我收到了关于我提交给 Easymock sourceforge 站点的错误的答复,开发人员已确认这确实是此版本 Easymock 的错误。

这确实是一个错误。即使已经完成捕获也已完成。当前的解决方法是实现您自己的捕获对象并覆盖 setValue 来执行此操作:

@Override
public void setValue(T value) {
  if(!hasCaptured()) {
    super.setValue(value);
  }
}
于 2009-02-20T14:09:26.130 回答
1

我在玩你的测试,无法解决。但是,我扩展了 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 

对不起,我不能帮助你更多。这可能确实是简单模拟中的一个错误。

于 2009-02-19T18:58:52.417 回答
0

您也可以尝试使用 EasyMock.createNiceMock(...) 代替 EasyMock.createStrictMock(...) 或 EasyMock.createMock(...)。

虽然,我同意它看起来更像是 createMock 的错误。

于 2009-02-19T17:51:49.803 回答
0

我认为这是一个更适合基于状态的测试的问题。使用 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();
   }
}
于 2009-06-29T02:56:30.307 回答
0

简而言之,这对我有用:

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

于 2015-02-20T18:27:06.823 回答
-1

而不是调用EasyMock.createStrictMock(...)只需调用EasyMock.createMock(...)。应该能解决你的问题。

于 2009-02-19T16:30:27.670 回答