Статьи

Когда заменить модульные тесты интеграционными тестами

Давно я думал об интеграции против модульного тестирования. Много гуглят, вопросы по переполнению стека и поиску во многих книгах. В этом посте я хотел бы поделиться с вами информацией, которую я нашел, и какое решение я приму к этому.

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

  1. Лучшие практики интеграционного тестирования
  2. Интеграция против модульного тестирования
  3. Junit: расщепление интеграционного теста и юнит-тесты
  4. Что такое интеграционный тест?

полезно получить хорошее понимание обеих терминологий.

Модульное тестирование широко используется в области Java, и большинство проектов в настоящее время также обеспечивает покрытие кода и модульное тестирование. Интеграционное тестирование — это относительно новая и неправильно понятая концепция. Даже через это практикуется намного меньше, чем, модульное тестирование может быть различным использованием этого. Давайте возьмем простую историю пользователя и вернемся к обоим.

Давайте рассмотрим это с историей пользователя

Пользователь выдаст INPUT в форме пользовательского интерфейса, и когда нажата кнопка отправки, выход PROCESSED должен быть показан на следующей странице. Поскольку результаты должны быть редактируемыми, в базе данных должны быть сохранены как INPUT, так и OUTPUT.

Технический дизайн

Предположим, что наше приложение будет быстро расти в будущем, и мы разработаем его сейчас, помня об этом.

Как показано на рисунке выше, это стандартная 4-уровневая конструкция с view, service, dao. Он имеет прикладной уровень, который содержит логику преобразования входных данных в выходные. Для реализации истории мы написали 5 методов (1 в сервисе, 2 дао для сохранения ввода и вывода, 1 содержит бизнес и 1 метод в слое представления для подготовки ввода.)

Написание некоторых юнит-тестов

Если мы собираемся провести юнит-тестирование истории, нам нужно написать 5 тестов. Поскольку разные слои являются зависимыми, нам может понадобиться использовать фиктивные объекты для тестирования. Но кроме одного метода на прикладном уровне, который выполняет исходный процесс, есть ли необходимость в модульном тестировании другой части? Например, метод,

1
2
3
4
public void saveInput(Input input){ 
           Session session = sessionFactory.getCurrentSession(); 
           session.save(input); 
 }

Когда вы тестируете этот модуль, вы обычно используете фиктивный объект sessionFactory, и код всегда будет работать. Следовательно, я не вижу особого смысла в проведении здесь модульного теста. Если вы внимательно наблюдаете, кроме прикладного уровня, все остальные методы будут аналогичны тем, которые мы обсуждали.

Чего мы можем достичь с помощью интеграционного теста?

Прочитайте здесь, как руководство для интеграционного теста. Как мы видели, большинство юнит-тестов для этой истории не были эффективными. Но мы не можем пропустить тестирование, так как хотим выяснить охват кода и сделать наш тест самоконтролируемым. По словам Мартина Флауэр в его статье о непрерывной интеграции, вы должны написать код, который может протестировать другой код. Я упал хорошие интеграционные тесты могут сделать это для вас.

Давайте напишем простой интеграционный тест для этой ситуации,

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
@Configurable(autowire = Autowire.BY_NAME)  
 @RunWith(SpringJUnit4ClassRunner.class)  
 @ContextConfiguration(locations = {"classpath:applicationContext.xml"}) 
 public class SampleIntTest { 
      @Autowired 
      private SamService samService; 
      @Test 
      public void testAppProcessing(){ 
      Input input = new Input(); 
      //prepare input for the testing. 
      Output output = samService.processInputs(input); 
      //validate outpt gainst the given input. 
      if(!isValidate(input,output)){ 
           Assert.fail("Validation failed!"); 
      
 }

Я пропустил слой представления здесь, поскольку это не так актуально. Мы ожидаем INPUT от пользовательского интерфейса в компоненте Input, и это будет у нас на уровне сервиса. Здесь, с помощью этого небольшого количества кода, вы можете достичь полной функциональности приложения на уровне сервиса.

Для интеграционных тестов предпочтительно использовать базу данных в памяти, такую ​​как H2. Если структура таблицы сложна, это может быть невозможно в этом случае, вы можете использовать тестовый экземпляр БД и подготовить сценарий для удаления всех данных и запустить его как часть теста, чтобы восстановить состояние БД. Это важно, потому что при следующем запуске те же данные будут сохранены снова.

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

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

Так что, как всегда, JEE делает выбор и придерживается его. Последние несколько месяцев мы тренировались в наших командах, и это действительно идет хорошо. В настоящее время мы сделали интеграционные тесты обязательными, а юнит-тесты — обязательными. Всегда просматривайте покрытие кода и убедитесь, что вы получаете хорошее покрытие в ядре системы (в нашем случае LogicalProcesser).

Ссылка: Когда заменить модульные тесты интеграционным тестом от нашего партнера JCG Ману П.К. в блоге «Объектно-ориентированная жизнь» .

Статьи по Теме :