Метод повторной заглушки Mockito уже заглушен - PullRequest
10 голосов
/ 15 ноября 2010

У меня возникла проблема с мокито. Я занимаюсь разработкой веб-приложения. В моих тестах управление пользователями является насмешкой. В некоторых случаях мне приходится изменять пользователя, возвращенного методом getLoggedInUser().

Проблема в том, что мой метод getLoggedInUser() может также выдавать AuthenticationException.

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

when(userProvider.getLoggedInUser()).thenReturn(user);

выдает исключение, так как userProvider.getLoggedInUser() уже заглушен с thenTrow()

Можно ли как-то сказать when методу не заботиться об исключениях?

Заранее спасибо - Иштван

Ответы [ 4 ]

16 голосов
/ 14 июня 2012

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

when(mock.someMethod("some arg"))
    .thenThrow(new RuntimeException())
    .thenReturn("foo");

http://docs.mockito.googlecode.com/hg/latest/org/mockito/Mockito.html#stubbing_consecutive_calls

5 голосов
/ 11 мая 2017

Есть ли способ сказать, когда метод не заботится об исключениях?

Чтобы ответить на этот вопрос:

import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.powermock.api.mockito.PowerMockito.mock;
import static org.powermock.api.mockito.PowerMockito.when;

import org.junit.Test;
import org.mockito.Mockito;

import java.util.ArrayList;

public class MyTest {

    @Test
    public void testA() {

        // setup
        ArrayList<Object> list = mock(ObjectArrayList.class);
        when(list.indexOf(any())).thenReturn(6);
        when(list.indexOf(any())).thenReturn(12);

        // execute
        int index = list.indexOf(new Object());

        // verify
        assertThat(index, is(equalTo(12)));
    }

    @Test
    public void testB() {

        // setup
        ArrayList<Object> list = mock(ObjectArrayList.class);
        when(list.add(any())).thenThrow(new AssertionError("can't get rid of me!"));
        when(list.add(any())).thenReturn(true);

        // execute
        list.add(new Object());
    }

    @Test
    public void testC() {

        // setup
        ArrayList<Object> list = mock(ObjectArrayList.class);
        when(list.add(any())).thenThrow(new AssertionError("can't get rid of me!"));
        Mockito.reset(list);
        when(list.add(any())).thenReturn(true);

        // execute
        list.add(new Object());
    }

    /**
     * Exists to work around the fact that mocking an ArrayList<Object>
     * requires a cast, which causes "unchecked" warnings, that can only be suppressed...
     */
    class ObjectArrayList extends ArrayList<Object> {

    }
}

TestB не удалосьиз-за того, что ты не можешь избавиться от этого.TestC показывает, как метод reset может использоваться для сброса макета и удаления для него команды thenThrow.

Обратите внимание, что сброс не всегда работает в некоторых более сложных примерах, которые у меня есть,Я подозреваю, что это может быть потому, что они используют PowerMockito.mock, а не Mockito.mock?

3 голосов
/ 15 ноября 2010

Моя первая реакция на ваш вопрос - звучит так, будто вы пытаетесь сделать слишком много за один тест.

Для простоты тестирования и простоты каждый тест должен проверять только одну вещь.Это то же самое, что и Принцип единой ответственности .Я часто нахожу программистов, пытающихся проверить несколько вещей в одном тесте, и у меня возникают всевозможные проблемы из-за этого.Таким образом, каждый из ваших методов модульного тестирования должен следовать этому потоку:

  1. Настройка отдельного сценария для теста.
  2. Выполните вызов тестируемого класса, чтобы вызвать тестируемый код.
  3. Проверьте поведение.

Так что в вашем случае я бы ожидал увидеть как минимум два теста.Тот, где getLoggedInUser() возвращает пользователя, а другой, где getLoggedInUser() выдает исключение.Таким образом, у вас не будет проблем с попыткой смоделировать различное поведение в макете.

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

2 голосов
/ 15 ноября 2010

Похоже, вам, возможно, придется использовать пользовательский ответ. Вот пример .

...