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

Итак, я создаю фиктивный объект как статическую переменную на уровне класса, вот так ... В одном тесте я хочу, чтобы 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, что означает, что мне придется выполнять цепочку в каждом тесте.


person Polaris878    schedule 18.11.2010    source источник


Ответы (5)


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

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

person shoebox639    schedule 18.11.2010

Вы также можете Заглушка Последовательные вызовы (№10 в API 2.8.9). В этом случае можно использовать несколько вызовов 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
    }
}
person Tony R    schedule 19.05.2011
comment
Я думаю, вы также можете воспользоваться тем фактом, что .thenReturn () принимает varargs, поэтому код можно сократить до: when (mockFoo.someMethod ()). ThenReturn (0, 1, -1); - person Justin Muller; 11.06.2012
comment
@JustinMuller - я думаю, это заслуживает отдельного ответа (в отличие от комментария) - person Brian Agnew; 11.11.2014
comment
Отличный ответ. Сэкономил мое время! :) - person vyakhir; 16.07.2015
comment
В данном случае это неправильный ответ. Если вы заглушите этот метод, чтобы он возвращал 0 и 1, тогда все будет в порядке, если вы запустите test1, а затем test2. Но может оказаться, что ваша среда непрерывной интеграции будет запускать тесты в другом порядке. Или может случиться так, что вы захотите запустить test2 самостоятельно, без предварительного запуска test1, и в этом случае произойдет сбой. Модульные тесты должны всегда быть независимыми друг от друга; и не должно никогда быть зависимости между отдельными тестами или зависимости от определенного порядка тестов. В то время как объединение thenReturn операторов в цепочку ... - person Dawood ibn Kareem; 21.07.2015
comment
... имеет свое применение, как и использование varargs для одного thenReturn, это неправильное решение в данном конкретном случае. Мне кажется, что орды проголосовавших здесь, скорее всего, не поняли вопроса. - person Dawood ibn Kareem; 21.07.2015
comment
Сам Junit не обеспечивает тестовый заказ без @FixMethodOrder - person Roger; 15.10.2015
comment
@DavidWallace, насколько мне известно, тестовый класс создается для каждого теста, а методы, отмеченные @Before, запускаются перед каждым тестом, поэтому я не вижу здесь проблемы с порядком тестирования. Возможно, ответ был отредактирован после вашего комментария. Или я что-то не так понимаю? - person lex82; 21.10.2016
comment
Не знал, что вы можете соединить такие возвраты, очень приятно, спасибо! - person EM-Creations; 13.11.2017
comment
также, если вы используете spy (), вам понадобится это: doReturn (obj1) .doReturn (obj2) .when (this.client) .somemethod (); - person fl0w; 07.03.2018

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

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

or

when(mockFoo.someMethod())
        .thenReturn(obj1, obj2)
        .thenThrow(new RuntimeException("Fail"));
person Nagy Attila    schedule 24.05.2018

Или еще чище:

when(mockFoo.someMethod()).thenReturn(obj1, obj2);
person pedromorfeu    schedule 24.10.2018
comment
Это должен быть ответ. - person Ikthiander; 07.05.2019

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

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

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

.

Для классических моков:

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

или с созданным исключением:

when(mockFoo.someMethod())
        .thenReturn(obj1)
        .thenThrow(new IllegalArgumentException())
        .thenReturn(obj2, obj3);
person fl0w    schedule 07.03.2018