Знакомство с фронтенд-тестированием. Часть четвертая. Интеграционное тестирование
В этот раз мы рассмотрим интеграционное тестирование. Это тесты, которые проверяют совместную работу нескольких модулей приложения.
11К открытий11К показов
Рассказывает Гил Тайяр, автор блога на Hackernoon
Мы рассмотрели два вида тестирования: юнит-тестирование различных модулей и E2E-тестирование всего приложения. Но между этими двумя этапами тестирования происходят и другие. Я, как и многие другие, называю такие тесты интеграционными.
Несколько слов о терминологии
Много общаясь с любителями разработки через тестирование, я пришёл к выводу, что они имеют другое определение для термина «интеграционные тесты». С их точки зрения, интеграционный тест проверяет «внешний» код, то есть тот, который взаимодействует с «внешним миром», миром приложения.
Поэтому, если их код использует Ajax или localStorage, или IndexedDB и, следовательно, не может быть протестирован с помощью юнит-тестов, они оборачивают этот функционал в интерфейс и мокают этот интерфейс для юнит-тестов, а тестирование реальной реализации интерфейса называют «интеграционным тестом». С этой точки зрения «интеграционный тест» просто тестирует код, который взаимодействует с «реальным миром» вне тех юнитов, которые работают без учета реального мира.
Я, как и многие другие, склонен использовать понятие «интеграционные тесты» для обозначения тестов, которые проверяют интеграцию двух или более юнитов (модулей, классов и т. д.). При этом неважно, скрываете ли вы реальный мир через замоканные интерфейсы.
Мое эмпирическое правило о том, следует ли использовать реальные реализации Ajax и других операций I/O (ввода-вывода) в интеграционных тестах, заключается в следующем: если вы можете это сделать и тесты все еще выполняются быстро и не ведут себя странно, то проверяйте I/O. Если операция I/O сложная, медленная или просто странная, то используйте в интеграционных тестах mock-объекты.
В нашем калькуляторе, к счастью, единственным реальным I/O является DOM. Нет вызовов Ajax и других причин писать «моки».
Фейковый DOM
Возникает вопрос: нужно ли писать фейковый DOM в интеграционных тестах? Применим моё правило. Использование реального DOM сделает тесты медленными? К сожалению, ответ — «да»: использование реального DOM означает использование реального браузера, что делает тесты медленными и непредсказуемыми.
Мы отделим большую часть кода от DOM или протестируем всё вместе в E2E-тестах? Оба варианта не оптимальны. К счастью, есть третье решение: jsdom. Этот замечательный и удивительный пакет делает именно то, чего от него ждёшь — реализует DOM в NodeJS.
Он работает, он быстр, он запускается в Node. Если вы используете этот инструмент, то можете перестать рассматривать DOM как «I/O». А это очень важно, ведь отделить DOM от фронтенд-кода сложно, если не невозможно. (Например, я не знаю, как сделать это.) Я предполагаю, что jsdom был написан именно для запуска фронтенд-тестов под Node.
Давайте посмотрим, как он работает. Как обычно, есть инициализирующий код и есть тестовый код, но на этот раз мы начнём с тестового. Но перед этим — отступление.
Отступление
Эта часть является единственной частью серии, которая ориентирована на конкретный фреймворк. И фреймворк, который я выбрал — это React. Не потому, что это лучший фреймворк. Я твердо верю, что нет такого понятия. Я даже не считаю, что существуют лучшие фреймворки для конкретных случаев использования. Единственное, во что я верю — люди должны использовать среду, в которой им наиболее комфортно работать.
И фреймворком, с которым мне наиболее комфортно работать, является React, поэтому следующий код написан на нём. Но, как мы увидим, интеграционные тесты фронтенда с использованием jsdom должны работать во всех современных фреймворках.
Вернемся к использованию jsdom.
Использование jsdom
Интересными являются строки с 10 по 14. В строке 10 мы визуализируем компонент CalculatorApp
, который (если вы следите за кодом в репозитории) также отображает компоненты Display
и Keypad
.
Затем мы проверяем, что в строках 12 и 14 элемент в DOM показывает на дисплее калькулятора начальное значение, равное 0.
И этот код, который работает под Node, использует document
! Глобальная переменная document
является переменной браузера, но вот она здесь, в NodeJS. Чтобы эти строки работали, требуется очень большой объем кода. Этот очень большой объем кода, который находится в jsdom, является, по сути, полной реализацией всего, что есть в браузере, за вычетом самого рендеринга!
Строка 10, которая вызывает ReactDom для визуализации компонента, также использует document
(и window
), так как ReactDom часто использует их в своем коде.
Итак, кто создает эти глобальные переменные? Тест — давайте посмотрим на код:
В строке 3 мы создаём простой document
, который содержит лишь div
.
В строке 4 мы создаём глобальное window
для объекта. Это нужно React.
Функция cleanup
удалит эти глобальные переменные, и они не будут занимать память.
В идеале переменные document
и window
должны быть не глобальными. Иначе мы не сможем запустить тесты в параллельном режиме с другими интеграционными тестами, потому что все они будут переписывать глобальные переменные.
К сожалению, они должны быть глобальными — React и ReactDom нуждаются в том, чтобы document
и window
были именно такими, поскольку вы не можете им их передать.
Обработка событий
А как насчет остальной части теста? Давайте посмотрим:
Остальная часть теста проверяет сценарий, в котором пользователь нажимает «42 * 2 =» и должен получить «84».
И он делает это красивым способом — получает элементы, используя известную функцию querySelector
, а затем использует click
, чтобы щелкнуть по ним. Вы даже можете создать событие и иницировать его вручную, используя что-то вроде:
Но встроенный метод click
работает, поэтому мы используем его.
Так просто!
Проницательный заметит, что этот тест проверяет точно то же самое, что и E2E-тест. Это правда, но обратите внимание, что этот тест примерно в 10 раз быстрее и является синхронным по своей природе. Его гораздо проще писать и гораздо легче читать.
А почему, если тесты одинаковы, нужен интеграционный? Ну, просто потому, что это учебный проект, а не настоящий. Два компонента составляют всё приложение, поэтому интеграционные и E2E-тесты делают одно и то же. Но в реальном приложении E2E-тест состоит из сотен модулей, тогда как интеграционные тесты включают в себя несколько, быть может, 10 модулей. Таким образом, в реальном приложении будет около 10 E2E-тестов, но сотни интеграционных тестов.
Другие статьи серии
11К открытий11К показов