предисловие
Когда разработка дошла до стадии написания юнит-тестов, оказалось, что тестируемые методы содержат зависимости: вызовы RPC внешнего интерфейса, вызовы БД. В некоторых случаях, когда некоторые зависимости нестабильны или не могут быть вызваны в тестовой среде, вариант использования иногда не выполняется.
Еще один момент, многие варианты использования написаны в начале тестовых случаев.@SpringRunTest
Аннотация тестового примера приводит к запуску всего контейнера Spring при запуске тестового примера, в результате запуск тестового примера происходит очень медленно. При запуске юзкейса в некоторых относительно больших проектах даже запуск контейнера занимает 5-6 минут каждый раз.Постепенно я не выношу такую операцию.Я волнуюсь каждый раз, когда меняю строчку кода, т.к. если я ошибаюсь, я должен сделать это снова.Подождите еще 5-6 минут, чтобы увидеть результаты. Позже я посоветовался с коллегами, поискал в Интернете и нашел относительно быстрое и безопасное решение с использованием фреймворка Mock:Mockito, учиться и практиковаться в течение определенного периода времени, а также резюмировать метод использования.
Mockito
Mockito в настоящее время является самым популярным фреймворком для модульного тестирования.
Что такое Мок
Буквальное значение Mock заключается в том, чтобы имитировать, виртуальный, в модульном тестировании использовать Mock для виртуализации внешнего зависимого объекта.
Для некоторых объектов (например, внешних служб), которые нелегко создать или получить в модульном тестировании, использование фиктивного объекта для создания может снизить сложность теста и заботиться только о текущем методе модульного тестирования.
Зачем использовать макет
Целью модульного тестирования является проверка правильности единицы кода, что действительно необходимо проверить, так это правильность вывода, соответствующего вводу, или нет. Если будут введены внешние зависимые сервисы, сложность исходного модуля возрастет, а содержание других функций будет неявно смешано в модуле.
Используя объекты Mock для модульного тестирования, разработчики могут заботиться только о тестируемом коде.
Пример использования
Взгляните на пример кода, рассмотрите следующий сценарий:
- Проверить интерфейс для получения информации о пользователе: в том числе ID пользователя, никнейм пользователя, является ли он vip
- Нужно ли получать vip из внешней службы VIPService, вызываемой через RPC, если тестовая среда имеет низкую производительность компьютера или плохую сеть, вариант использования будет нестабильным.
- Напишите модульный тест, чтобы определить, правильно ли возвращается информация о VIP-пользователе.
Требование состоит в том, чтобы определить, является ли формат, возвращаемый интерфейсом получения пользовательской информации, правильным, независимо от возвращаемого значения интерфейса vip, если поля, возвращаемые интерфейсом vip, передаются прозрачно.Код теста выглядит следующим образом:
@RunWith(PowerMockRunner.class)
public class UserServiceTest {
@InjectMocks
private UserService userService;
@Mock
private VIPService vipService;
@Test
public void getUserInfo() {
Mockito.when(vipService.isVip(Mockito.anyString())).thenReturn(true);
Result result = userService.getUserInfo("123");
Assert.assertEquals(true, result.getData().get("isVip"));
}
}
Объясните несколько аннотаций, используемых в приведенном выше коде.
@Mock: Создать макет
@InjectMocks: экземпляр Mock, в который будут внедрены остальные макеты, созданные с помощью аннотации Mock.
Mockito.when(...).thenReturn(...): Mock метод, когда внутри, если условие выполнено, вернуть результаты thenReturn указано.
В этом коде используйте@Mock
Аннотация создает экземпляр VipService, используя@InjectMock
После создания UserService экземпляр vipService, созданный Mock, будет внедрен в экземпляр UserService, а поведение vipService может быть смоделировано при написании тестовых случаев.
Mockito.when(vipService.isVip(Mockito.anyString())).thenReturn(true);
Этот код означает, что какие бы параметры ни были переданы в метод vipService.isVip, метод вернет true, так что это не повлияет на нормальную проверку интерфейса для получения информации о пользователе, а также вы можете использовать утверждения для проверки возвращаемых данные.
Сценарии, с которыми столкнулись
Выше приведен самый простой пример использования Mockito на практике.В процессе использования в производственной среде возникнут различные требования, которые необходимо выполнить.Ниже приведены сценарии, с которыми столкнулся автор.
имитация исключения
Этот сценарий заключается в том, что метод объявляет, что может быть выброшено исключение А, и существует много возможностей для исключения А, и разные исключения соответствуют разным сообщениям.Чтобы проверить функцию после выдачи определенного исключения А, необходимо смоделировать метод throwing Выдается исключение указанного сообщения.
Способ его использования состоит в том, чтобы определитьRule
Атрибут аннотации, когда он используется, устанавливает тип исключения, создаваемого throw, и сообщение, которое оно несет. Краткий код выглядит следующим образом:
class AException extends RuntimeException {
private final int code;
public AException(int code, String msg) {
super(msg);
this.code = code;
}
}
@RunWith(PowerMockRunner.class)
public class MockExceptionTest {
@Rule
public ExpectedException thrown = ExpectedException.none();
@Test
public void mockException() {
thrown.expect(AException.class);
thrown.expectMessage("expected message");
// test code
}
}
имитация пустого метода
Смоделируйте пустой метод, это относительно просто, то есть вызватьdoNothing().when()...
.
имитация статического метода
Если вы хотите имитировать статические методы, сначала добавьте аннотации в начале класса:@PrepareForTest({ClassNameA.class})
.
Прежде чем потребуется метод класса Mock, добавьте код:PowerMockito.mockStatic(ClassNameA.class);
, и тогда вы можете счастливо издеваться. Краткий код выглядит следующим образом:
class ClassNameA {
public static int methodA() {
// code
return ret;
}
}
@RunWith(PowerMockRunner.class)
@PrepareForTest({ClassNameA.class})
public class MockStaticClassTest {
@Test
public void mockStaticMethod() {
PowerMockito.mockStatic(ClassNameA.class);
Mockito.when(ClassNameA.methodA()).thenReturn(1);
// test code
}
}
частичный макет
Для некоторых сценариев в модульном тесте требуется определенный метод Mock, а определенный метод следует обычной логике. Для такого рода операций просто нужно запустить контейнер. В настоящее время нет подходящего метода для такого рода операций. Если есть лучший способ Метод хлопотно давать указатели. Текущий подход автора состоит в том, чтобы разбить исходный метод на более мелкие блоки, чтобы каждый из них можно было смоделировать, а весь код фактически выполнялся во время интеграционного теста.
Это сцена, с которой автор сталкивается в ежедневном развитии.
Суммировать
Модульное тестирование — это проверочная работа для проверки правильности наименьшей единицы логики кода Написание модульных тестов — очень необходимая работа для обнаружения ошибок в коде, обеспечения стабильности системы и рефакторинга, а также может заранее обнаружить некоторые скрытые вещи.
Лучшие практики JUnitВ этой статье упоминается, что Mock все внешние службы и состояния:
Макет всех внешних сервисов и состояния В противном случае поведение этих внешних служб перекрывает несколько тестов, а данные о состоянии означают, что разные модульные тесты могут влиять на результаты друг друга. когда ваша база данных или сетевое соединение активны.
Also, this is important because you would not love to debug the test cases which are actually failing due to bugs in some external system.
Поэтому максимально используйте Mock для модульного тестирования с внешними сервисами.
Оригинал статьи, ограниченный стиль написания, недостаток знаний и знаний, если есть неточности в статье, сообщите пожалуйста.
Если эта статья была вам полезна, пожалуйста, поставьте лайк, спасибо
Для более интересного контента, пожалуйста, обратите внимание на личный публичный номер.
Справочная статьяJUnit Best Practices Guide