How to tell a Mockito mock object to return something different the next time it is called?
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.
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
}
}
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"));
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.
Or, even cleaner:
when(mockFoo.someMethod()).thenReturn(obj1, obj2);
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);
精彩评论