How to tell a Mockito mock object to return something different the next time it is called?

JavaUnit TestingJunitMockingMockito

Java Problem Overview


So, I'm creating a mock object as a static variable on the class level like so... In one test, I want Foo.someMethod() to return a certain value, while in another test, I want it to return a different value. The problem I'm having is that it seems I need to rebuild the mocks to get this to work correctly. I'd like to avoid rebuilding the mocks, and just use the same objects in each test.

class TestClass {

    private static Foo mockFoo;

    @BeforeClass
    public static void setUp() {
        mockFoo = mock(Foo.class);
    }

    @Test
    public void test1() {
        when(mockFoo.someMethod()).thenReturn(0);

        TestObject testObj = new TestObject(mockFoo);

        testObj.bar(); // calls mockFoo.someMethod(), receiving 0 as the value

    }

    @Test
    public void test2() {
        when(mockFoo.someMethod()).thenReturn(1);

        TestObject testObj = new TestObject(mockFoo);

        testObj.bar(); // calls mockFoo.someMethod(), STILL receiving 0 as the value, instead of expected 1.

    }

}

In the second test, I'm still receiving 0 as the value when testObj.bar() is called... What is the best way to resolve this? Note that I know I could use a different mock of Foo in each test, however, I have to chain multiple requests off of mockFoo, meaning I'd have to do the chaining in each test.

Java Solutions


Solution 1 - Java

You could also Stub Consecutive Calls (#10 in 2.8.9 api). In this case, you would use multiple thenReturn calls or one thenReturn call with multiple parameters (varargs).

import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import org.junit.Before;
import org.junit.Test;

public class TestClass {

	private Foo mockFoo;

    @Before
    public void setup() {
    	setupFoo();
    }

    @Test
    public void testFoo() {
    	TestObject testObj = new TestObject(mockFoo);

    	assertEquals(0, testObj.bar());
    	assertEquals(1, testObj.bar());
    	assertEquals(-1, testObj.bar());
    	assertEquals(-1, testObj.bar());
    }

	private void setupFoo() {
	    mockFoo = mock(Foo.class);

    	when(mockFoo.someMethod())
			.thenReturn(0)
		    .thenReturn(1)
	    	.thenReturn(-1); //any subsequent call will return -1

        // Or a bit shorter with varargs:
    	when(mockFoo.someMethod())
			.thenReturn(0, 1, -1); //any subsequent call will return -1
    }
}

Solution 2 - Java

For all who search to return something and then for another call throw exception:

when(mockFoo.someMethod())
        .thenReturn(obj1)
        .thenReturn(obj2)
        .thenThrow(new RuntimeException("Fail"));

or

when(mockFoo.someMethod())
        .thenReturn(obj1, obj2)
        .thenThrow(new RuntimeException("Fail"));

Solution 3 - Java

First of all don't make the mock static. Make it a private field. Just put your setUp class in the @Before not @BeforeClass. It might be run a bunch, but it's cheap.

Secondly, the way you have it right now is the correct way to get a mock to return something different depending on the test.

Solution 4 - Java

Or, even cleaner:

when(mockFoo.someMethod()).thenReturn(obj1, obj2);

Solution 5 - Java

For Anyone using spy() and the doReturn() instead of the when() method:

what you need to return different object on different calls is this:

doReturn(obj1).doReturn(obj2).when(this.spyFoo).someMethod();

.

For classic mocks:

when(this.mockFoo.someMethod()).thenReturn(obj1, obj2);

or with an exception being thrown:

when(mockFoo.someMethod())
        .thenReturn(obj1)
        .thenThrow(new IllegalArgumentException())
        .thenReturn(obj2, obj3);

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionPolaris878View Question on Stackoverflow
Solution 1 - JavaTony RView Answer on Stackoverflow
Solution 2 - JavaNagy AttilaView Answer on Stackoverflow
Solution 3 - Javashoebox639View Answer on Stackoverflow
Solution 4 - JavapedromorfeuView Answer on Stackoverflow
Solution 5 - Javafl0wView Answer on Stackoverflow