Подтвердить что ты не робот

Использование Mockito для заглушения и выполнения методов тестирования

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

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

Вот что я пытался сделать:

  • Создайте объект Mockito моего агента следующим образом:

    MyProcessingAgent mockMyAgent = Mockito.mock(MyProcessingAgent.class);

  • Настроить заглушки (надеюсь, правильный термин) с помощью Mockito.when вот так:

    Mockito.when(mockMyAgent.otherMethod(Mockito.any(arg1)).thenReturn(requiredReturnArg);

  • Попробуйте выполнить мой метод следующим образом:

    List myReturnValue = mockMyAgent.methodThatNeedsTestCase();

Я ожидал вещей в myReturnValue, но вместо этого получил 0, поэтому я попытался отладить. Когда я вызываю метод, он никогда не выполняется. У меня есть точка отладки в первой строке метода, которая никогда не затрагивается.

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

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

4b9b3361

Ответ 1

Вы вводите в заблуждение Mock с Spy.

В mock все методы заштрихованы и возвращают "умные типы возврата". Это означает, что вызов любого метода в издеваемом классе ничего не сделает, если вы не укажете поведение.

В шпионах исходная функциональность класса по-прежнему существует, но вы можете проверять вызовы методов в шпионаже, а также на поведение метода переопределения.

Вы хотите

MyProcessingAgent mockMyAgent = Mockito.spy(MyProcessingAgent.class);

Быстрый пример:

static class TestClass {

    public String getThing() {
        return "Thing";
    }

    public String getOtherThing() {
        return getThing();
    }
}

public static void main(String[] args) {
    final TestClass testClass = Mockito.spy(new TestClass());
    Mockito.when(testClass.getThing()).thenReturn("Some Other thing");
    System.out.println(testClass.getOtherThing());
}

Выход:

Some Other thing

Примечание. Вы действительно должны попытаться высмеять зависимости для тестируемого класса не самого класса.

Ответ 2

Итак, идея насмешки над тестируемым классом - анафима к практике тестирования. Вы НЕ должны этого делать. Поскольку вы это сделали, ваш тест вводит Mockito насмешливые классы, а не ваш тестируемый класс.

Шпионаж также не работает, потому что это обеспечивает только оболочку/прокси-сервер вокруг класса spied. После выполнения внутри класса он не пройдет через прокси и, следовательно, не попадет в шпион. UPDATE: хотя я считаю, что это справедливо для прокси-серверов Spring, похоже, это не относится к шпионам Mockito. Я установил сценарий, в котором метод m1() вызывает m2(). Я шпионить объект и заглушить m2() до doNothing. Когда я вызываю m1() в своем тесте, m2() этого класса не достигается. Мокито вызывает заглушку. Поэтому использование шпиона для выполнения того, что задается, возможно. Тем не менее, я бы повторил, что считаю это плохой практикой (ИМХО).

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

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

Ответ 3

Ты почти понял это. Проблема заключается в том, что Class Under Test (CUT) не создан для модульного тестирования - на самом деле это не было TDD 'd.

Подумайте об этом так: hellip;

  • Мне нужно проверить функцию класса - позвольте мне его myFunction
  • Эта функция выполняет вызов функции в другом классе/службе/базе данных
  • Эта функция также вызывает другой метод в CUT

В unit test

  • Должен создать конкретный CUT или @Spy на нем
  • Вы можете @Mock использовать весь другой класс/службу/базу данных (т.е. внешние зависимости)
  • Вы можете заглушить другую функцию, вызванную в CUT, но на самом деле это не так, как нужно выполнить тестирование модулей.

Чтобы избежать выполнения кода, который вы не строго тестируете, вы можете абстрагировать этот код на то, что может быть @Mock ed.

В этом очень простом примере функция, создающая объект, будет трудно протестировать

public void doSomethingCool(String foo) {
    MyObject obj = new MyObject(foo);

    // can't do much with obj in a unit test unless it is returned
}

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

public void doSomethingCool(String foo) {
    MyObject obj = MyObjectService.getMeAnObject(foo);
}

поскольку MyObjectService можно высмеять, а также проверить, что .getMeAnObject() вызывается с переменной foo.