Год спустя, все еще борются с тестированием Unit vs Integration vs E2E

Недавно я посмотрел несколько выступлений на конференции AssertJS (которую я очень рекомендую), в том числе @kentcdodds "Написание тестов, не слишком много, в основном интеграция". Я работал над проектом Angular более года, написал несколько модульных тестов и только начал играть с Cypress, но я все еще чувствую разочарование по поводу интеграционных тестов и того, где проводить границы. Мне бы очень хотелось поговорить с каким-нибудь профессионалом, который занимается этим изо дня в день, но я не знаю, где я работаю. Так как я устал от того, что не могу понять это, я подумал, что просто спрошу мир здесь, потому что вы все фантастические.

Итак, в Angular (или React, или Vue и т. д.) У вас есть код компонента, а затем у вас есть шаблон HTML, и обычно они каким-то образом взаимодействуют. В коде компонента есть функции, которые можно тестировать, и с этой частью я согласен.

Я не совсем понял, как вы называете это интеграционным тестом, когда тестируете, как функция компонента изменяет пользовательский интерфейс? Если вы тестируете такие вещи, нужно ли это делать только в тестах E2E? Потому что Angular / Jasmine (или Jest) позволяет делать такие вещи, ссылаясь на пользовательский интерфейс:

const el = fixture.debugElement.queryAll(By.css('button'));
expect(el[0].nativeElement.textContent).toEqual('Submit')

Но значит ли это, что вам следует? И если да, то разве вы не учитываете это в своих тестах E2E?

Что касается интеграции с такими вещами, как услуги, как далеко вы зашли с интеграцией? Если вы имитируете фактический HTTP-вызов и просто проверяете, что он будет вызываться с правильными функциями, это интеграционный тест или все еще модульный тест?

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

Я знаю, что это становится все длиннее, но вот мой пример приложения:

Год спустя, все еще борются с тестированием Unit vs Integration vs E2E

Существует свойство hasNoProducts, которое устанавливается после выбора продукта и возврата данных с сервера (или нет, если их нет). Если hasNoProducts - истина, пользовательский интерфейс (через * ngIf) показывает это сообщение «Извините». Если false, становятся доступны другие варианты выбора. Эти параметры меняются в зависимости от выбранного продукта.

Итак, я знаю, что могу написать модульный тест и имитировать HTTP-запрос, чтобы проверить правильность настройки hasNoProducts. Но затем я хочу проверить, отображается ли сообщение или отображаются дополнительные параметры. И если есть данные, проверьте, что переключение продукта изменяет данные в других списках, которые впоследствии будут отображаться на экране. Если я сделаю это с помощью Angular / Jasmine, будет ли это интеграционным тестом, поскольку я «интегрирую» компонент и шаблон? Если нет, то какой будет интеграционный тест?

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

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
10
0
958
1

Ответы 1

Что отличает модульные тесты и интеграционные тесты (а затем тесты подсистем и системные тесты), так это цель, которую вы хотите достичь с помощью тестов.

Цель модульного тестирования - найти те ошибки в небольших фрагментах кода, которые могут быть обнаружены, если эти фрагменты кода изолированы. Обратите внимание, что это не означает, что вы действительно должны изолировать код, но это означает, что ваш фокус является изолированным кодом. В модульном тестировании макетирование очень распространено, поскольку оно позволяет стимулировать сценарии, которые иначе трудно протестировать, или ускоряет время сборки и выполнения и т. д., Но макетирование не является обязательным: например, вы не можете имитировать вызовы математическая функция sin() из стандартной библиотеки, потому что функция sin() не мешает вам достичь ваших целей тестирования. Но оставление функции sin() не превращает эти тесты в интеграционные. Строго говоря, у вас даже могут быть модульные тесты, в которых происходит реальный доступ к сети (если вы слишком ленивы, чтобы имитировать доступ к сети), но из-за недетерминизма, задержек и т. д. Эти модульные тесты будут медленными и ненадежными, это означает, что они просто не подходят для конкретного поиска ошибок в изолированном коде. Вот почему все говорят, что «если есть реальный доступ к сети, это не юнит-тест», что не формально, а практически правильно.

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

Что же тогда такое интеграционные тесты? Они определяются целью найти ошибки во взаимодействиях между (уже протестированными) компонентами. Такие ошибки могут возникать, например, из-за взаимных неправильных представлений разработчиков компонентов о том, как должен работать интерфейс. Например, в случае библиотечного компонента B, который используется из A: вызывает ли A функции из правильного компонента B (а не из C), происходят ли вызовы, когда B уже находится в правильном состоянии (B может не работать). инициализированы или в состоянии ошибки), выполняются ли вызовы в правильном порядке, указаны ли аргументы в правильном порядке и имеют ли значения в ожидаемой форме (например, индекс с нулевым основанием или индекс с одним основанием ?, null разрешен?), возвращаемые значения представлены в ожидаемой форме (возвращенный код ошибки или исключение) и имеют значения в ожидаемой форме? Это для одного сценария интеграции - есть много других, например, компонентов, обменивающихся данными через файлы (двоичные или текстовые? Какой маркер конца строки: unix, dos, ...?, ...).

Есть много возможных ошибок взаимодействия. Чтобы найти их, в интеграционном тестировании вы интегрируете реальные компоненты (настоящий A и настоящий B, без фиктивных, но, возможно, фиктивных для других компонентов) и стимулируете их таким образом, чтобы различные взаимодействия действительно имели место - в идеале всеми интересными способами, например , пытаясь принудительно задействовать некоторые граничные случаи во взаимодействии (передаваемый файл пуст, ...). Опять же, сам факт того, что тест работает с программным обеспечением, в которое интегрированы некоторые компоненты, не делает его интеграционным тестом: только если тест специально разработан для инициирования взаимодействий, так что ошибки в этих взаимодействиях становятся очевидными, тогда это интеграционный тест. .

Затем тесты подсистем (которые являются следующим уровнем) снова сосредотачиваются на оставшихся ошибках, то есть на тех ошибках, которые ни модульное тестирование, ни интеграционное тестирование не намерены обнаруживать. Примерами являются требования к компоненту C, которые не были учтены, когда C был разложен на A и B, или, если C построен с использованием какой-то устаревшей версии A, в которой все еще сохранялась какая-то ошибка. Однако при переходе от модульного тестирования через интеграцию От тестирования до тестирования подсистем и выше, сложно оставаться сосредоточенным: только иметь тесты на ошибки, которые не могли быть обнаружены раньше, а не, скажем, повторять модульные тесты на уровне подсистемы.

Другие вопросы по теме