Как сообщить моктовому объекту Mockito возвратить что-то другое при следующем его вызове?

Итак, я создаю mock-объект как статическую переменную на уровне класса, например... В одном тесте я хочу, чтобы Foo.someMethod() возвращал определенное значение, а в другом тесте я хочу, чтобы он возвращался другое значение. Проблема, с которой я сталкиваюсь, состоит в том, что мне кажется, что мне нужно перестроить макеты, чтобы заставить это работать правильно. Я бы хотел избежать перестройки издевок и просто использовать одни и те же объекты в каждом тесте.

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.

    }

}

Во втором тесте, я все еще получаю 0 в качестве значения при вызове testObj.bar()... Каков наилучший способ решить эту проблему? Обратите внимание, что я знаю, что в каждом тесте я мог бы использовать различный макет Foo, однако мне нужно связать несколько запросов с mockFoo, то есть мне нужно будет выполнить цепочку в каждом тесте.

Ответ 1

Прежде всего, не делайте макет статичным. Сделайте это частным полем. Просто поставьте свой класс setUp в @Before not @BeforeClass. Это может быть пучок, но это дешево.

Во-вторых, способ, которым у вас есть это прямо сейчас, - это правильный способ заставить макет вернуть что-то другое в зависимости от теста.

Ответ 2

Вы также можете Последовательные последовательные вызовы (# 10 в 2.8.9 api). В этом случае вы будете использовать несколько вызовов thenReturn или один вызов thenReturn с несколькими параметрами (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
    }
}

Ответ 3

Для всех, кто ищет что-то для возврата, а затем для другого исключения броска вызова:

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

или же

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

Ответ 4

Или даже чище:

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

Ответ 5

Для тех, кто использует spy() и doReturn() вместо метода when():

то, что вам нужно для возврата разных объектов при разных вызовах, это:

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

.

Для классических издевательств:

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