Использование 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?
Похоже, что мой текущий метод подхода - это не правильный стиль тестирования, но я не уверен, как двигаться вперед. Могу ли я высмеивать свой класс и запускать один метод как обычный, в то время как другие методы затуманиваются, чтобы возвращать мои данные, чтобы мне не приходилось иметь дело с доступом к данным во время тестирования этого метода?
Ответы
Ответ 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.