Java – Mocking inter-method dependencies

javamockingunit testing

I've recently started using mock objects in my tests, but I'm still very inexperienced with them and unsure of how to use them in some cases. At the moment I'm struggling with how to mock inter-method dependencies (calling method A has an effect on the results of method B), and whether it should even be mocked (in the sense of using a mocking framework) at all?

Take for example a Java Iterator? It is easy enough to mock the next() call to return the correct values, but how do I mock hasNext(), which depends on how many times next() has been called? Currently I'm using a List.Iterator as I could find no way to properly mock one.

Does Martin Fowler's distinction between mocks and stubs come into play here? Should I rather write my own IteratorMock?

Also consider the following example. The method to be tested calls mockObject.setX() and later on mockObject.getX(). Is there any way that I can create such a mock (without writing my own) which will allow the returned value of getX to depend on what was passed to setX?

Best Answer

In the general case I would follow the advice of djna above and set up the expectations for both methods. But for the example given I'd likely not use a mock but rather use the APIs to create a collection with the data I want in it and retrieve the iterator from that. (Arrays.asList(...).iterator()).

Edit: Re: set/get What else are you doing with this object? If it is a value object (only gets/sets) I'd not mock it. To much effort for no gain. If it is not then using easyMock:

import org.apache.commons.lang.mutable.MutableInt;
import org.easymock.IAnswer;
import org.junit.Test;
import static org.easymock.EasyMock.*;

public class TestSet {
    @Test
    public void testSetGet() {
        final MutableInt value = new MutableInt();

        GetSetId id = createMock(GetSetId.class);
        id.setID(anyInt());
        expectLastCall().andAnswer(new IAnswer<Object>() {

            @Override
            public Object answer() throws Throwable {
                Object[] arguments = getCurrentArguments();
                value.setValue((Integer) arguments[0]);
                return null;
            }

        });
        expect(id.getID()).andAnswer(new IAnswer<Integer>() {

            @Override
            public Integer answer() throws Throwable {

                return value.toInteger();
            }

        });

        replay(id);
        id.setID((int) (Math.random() * 100.0));
        System.out.println(id.getID());
        verify(id);
    }
}

interface GetSetId {
    public int getID();
    public void setID(int id);
}