First off, I'm very happy with EasyMock, it has saved me many hours of work.
Not sure if this is a bug or intended behaviour.
Having read bug 2060545
<quote>However, EasyMock behavior is perfectly normal. Captures doen't occur in
order. They occur when a call is matched.</quote>
What should happen in the case of a mock method with a single parameter that is called twice?
import static org.easymock.EasyMock.capture;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.createStrictMock;
import static org.easymock.EasyMock.eq;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import org.easymock.Capture;
import org.junit.Test;
public class MultipleCaptureTest {
@Test
public void testCaptureNonStrictControl(){
/*
* Should multiple same-type captures be allowed when order is
* not enforced?
*/
testCaptureHelper(createMock(IProcess.class));
}
@Test
public void testCaptureStrictControl(){
testCaptureHelper(createStrictMock(IProcess.class));
}
@SuppressWarnings("unchecked")
protected void testCaptureHelper(IProcess processMock){
Capture<?> capture1 = new Capture();
Capture<?> capture2 = new Capture();
processMock.process(capture(capture1));
processMock.process(capture(capture2));
replay(processMock);
processMock.process(new Object());
processMock.process(new Object());
verify(processMock);
assertTrue(capture1.hasCaptured());
assertTrue(capture2.hasCaptured());
assertFalse(capture1.getValue() == capture2.getValue());
}
public interface IProcess {
public void process(Object object);
}
}
Perhaps something like this would work....
public class Captures<t> implements IArgumentMatcher, Serializable {</t>
private static final long serialVersionUID = 1L;
private Capture<T> capture;
public Captures(Capture<T> captured) {
this.capture = captured;
}
public void appendTo(StringBuffer buffer) {
buffer.append("capture(").append(capture).append(")");
}
@SuppressWarnings("unchecked")
public boolean matches(Object actual) {
/*
* If the capture has already been done then this capture
* cannot be used
*/
if (!capture.hasCaptured()){
capture.setValue((T) actual);
return true;
} else {
return false;
}
}
}
Although this breaks one of the unit tests...
You are absolutely right. This is not the intended behavior. You fix seems to fix this (but as a side effect that I should look into) and doesn't exactly reflect what was my first intent.
Initially, if a Capture object was used twice, the last capture should be retained. In fact, maybe a capture list can be useful... The failing test fails because of this change of behavior.
I'll check what can be done.
I'm having the same problem. I'm calling myObject.mockMethod twice, and capture each parameter in its own Capture object. After verification, both Capture objects contain the last parameter passed to the mockObject.
Any hope for a fix? Tnx & keep up the great work!
Hi. I didn't fix it yet but will. I'll probably add an optional capture behavior to the capture object. Should be hopefully released soon.
Hi,
I got my code working with a dirty fix, much like Davids solution. I prevent the capture from getting a second value by overriding the setValue method:
class MyCapture<t> extends Capture<t> {</t></t>
}
Although this works in my particular case, I don't know what the effects will be if the order of the captures is rearranged. So a full-fledged solution is much appreciated.
To fix multiple captures I've created a MultipleCapture object (see below)
Now you can check the n-th call
MultipleCapture<string> capturedMessages = new MultipleCapture<string>();</string></string>
.. method calls
assertThat(capturedMessages.getValue(1), containsString("GROUP"));
assertThat(capturedMessages.getValue(2), containsString("QUESTION"));
The class:
public class MultipleCapture<t> extends Capture<t> {</t></t>