Question

public Object doSomething(Object o); which I want to mock. It should just return its parameter. I tried:

Capture<Object> copyCaptcher = new Capture<Object>();
expect(mock.doSomething(capture(copyCaptcher)))
        .andReturn(copyCatcher.getValue());

but without success, I get just an AssertionError as java.lang.AssertionError: Nothing captured yet. Any ideas?

Was it helpful?

Solution

I was looking for the same behavior, and finally wrote the following :

import org.easymock.EasyMock;
import org.easymock.IAnswer;

/**
 * Enable a Captured argument to be answered to an Expectation.
 * For example, the Factory interface defines the following
 * <pre>
 *  CharSequence encode(final CharSequence data);
 * </pre>
 * For test purpose, we don't need to implement this method, thus it should be mocked.
 * <pre>
 * final Factory factory = mocks.createMock("factory", Factory.class);
 * final ArgumentAnswer<CharSequence> parrot = new ArgumentAnswer<CharSequence>();
 * EasyMock.expect(factory.encode(EasyMock.capture(new Capture<CharSequence>()))).andAnswer(parrot).anyTimes();
 * </pre>
 * Created on 22 juin 2010.
 * @author Remi Fouilloux
 *
 */
public class ArgumentAnswer<T> implements IAnswer<T> {

    private final int argumentOffset;

    public ArgumentAnswer() {
        this(0);
    }

    public ArgumentAnswer(int offset) {
        this.argumentOffset = offset;
    }

    /**
     * {@inheritDoc}
     */
    @SuppressWarnings("unchecked")
    public T answer() throws Throwable {
        final Object[] args = EasyMock.getCurrentArguments();
        if (args.length < (argumentOffset + 1)) {
            throw new IllegalArgumentException("There is no argument at offset " + argumentOffset);
        }
        return (T) args[argumentOffset];
    }

}

I wrote a quick "how to" in the javadoc of the class.

Hope this helps.

OTHER TIPS

Well, the easiest way would be to just use the Capture in the IAnswer implementation... when doing this inline you have to declare it final of course.

MyService mock = createMock(MyService.class);

final Capture<ParamAndReturnType> myCapture = new Capture<ParamAndReturnType>();
expect(mock.someMethod(capture(myCapture))).andAnswer(
    new IAnswer<ParamAndReturnType>() {
        @Override
        public ParamAndReturnType answer() throws Throwable {
            return myCapture.getValue();
        }
    }
);
replay(mock)

This is probably the most exact way, without relying on some context information. This does the trick for me every time.

Captures are for testing the values passed to the mock afterwards. If you only need a mock to return a parameter (or some value calculated from the parameter), you just need to implement IAnswer.

See "Remi Fouilloux"s implementation if you want a reusable way of passing paramter X back, but ignore his use of Capture in the example.

If you just want to inline it like "does_the_trick"s example, again, the Capture is a red herring here. Here is the simplified version:

MyService mock = createMock(MyService.class);
expect(mock.someMethod(anyObject(), anyObject()).andAnswer(
    new IAnswer<ReturnType>() {
        @Override
        public ReturnType answer() throws Throwable {
            // you could do work here to return something different if you needed.
            return (ReturnType) EasyMock.getCurrentArguments()[0]; 
        }
    }
);
replay(mock)

Based on @does_the_trick and using lambdas, you can now write the following:

MyService mock = EasyMock.createMock(MyService.class);

final Capture<ParamAndReturnType> myCapture = EasyMock.newCapture();
expect(mock.someMethod(capture(myCapture))).andAnswer(() -> myCapture.getValue());

or without capture as @thetoolman suggested

expect(mock.someMethod(capture(myCapture)))
.andAnswer(() -> (ParamAndReturnType)EasyMock.getCurrentArguments()[0]);

Um, if I understand your question correctly I think you may be over complicating it.

Object someObject = .... ;
expect(mock.doSomething(someObject)).andReturn(someObject);

Should work just fine. Remember you are supplying both the expected parameter and returne value. So using the same object in both works.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top