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

Давайте посмотрим, как это может выглядеть в контексте Angular, используя встроенную в фреймворк внедрение зависимостей и TypeScript.

NB Я собираюсь использовать Nrwl Nx, чтобы раскрутить эти фрагменты кода в общем рабочем пространстве или монорепозитории (терминология, похоже, изменилась).

Если вы не знакомы с Nrwl Nx, вы должны проверить это! Я широко использовал их инструменты в работе, и после нескольких заминок могу настоятельно рекомендовать их. Смотрите здесь для немного устаревшего объяснения того, почему / как я использовал их вещи в прошлом.

В основном, однако, они предоставляют способ легкого создания нескольких приложений/библиотек из одного репозитория, поддерживая повторное использование кода между приложениями, с удобными инструментами, построенными поверх Angular CLI, для обработки модульного тестирования, e2e-тестирования, сборок и т. д., а также как куча генераторов для создания самоуверенных битов «лучшей практики» кода Angular/ngrx. (И вы получаете все это бесплатно!)

Однако метод, который я использую для заглушки зависимостей, в равной степени применим к «ванильному» приложению Angular.

Познакомьтесь с игроками

1) Наше основное приложение Angular. У него есть кнопка, которая при нажатии вызывает конечную точку getInformation нашего Slow Ass Api, а по завершении отображает результат (типа SlowInformation).

2) Наш Slow Ass API. Это отдельная библиотека TypeScript, предоставляющая один метод getInformation, который возвращает объект типа SlowInformation. (Не очень) умный момент заключается в том, что этот вызов будет имитировать непредсказуемую медлительность, возвращая данные после случайного промежутка времени от 0 мс до 10000 мс.

3) Наши тесты E2E. Я собираюсь использовать для них Кипарис, потому что он мне очень нравится. Если вы хотите использовать Транспортир, этот метод все равно будет работать, вместо этого вам просто нужно будет использовать метод executeScript для обращения к объекту окна. Кроме того, если вы создадите свое приложение с помощью Nrwl Nx, они настроят всю структуру кода и конфигурацию для поддержки Protractor или Cypress (вы можете выбрать как часть их интерактивного сценария установки).

Действие

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

Я заберу после того, как будет собран первоначальный скелет проекта. Как я уже упоминал, это было сделано с помощью расширений Nrwl Nx для Angular CLI. Если вам интересно, вы можете увидеть, что эти инструменты делают для вас в этом коммите.

Сгенерируйте slow-information-renderer приложение Angular (коммит):

Это использует другой скрипт Nx для создания полноценного приложения Angular, я решил использовать Jest и Cypress, поэтому он также настраивает проект тестирования e2e, который можно запустить с помощью npm run e2e

Генерируем компонент slow information renderer и slow information service (коммит)

Они будут нести ответственность за то, чтобы попросить пользователя нажать кнопку, что в конечном итоге вызовет наш сервис для вызова медленного API.

Опять же, это использует команды генератора для создания стандартного компонента с лучшими практиками.

Сгенерировать и записать slow ass api библиотеку (коммит)

Из-за чрезмерной интерактивной перебазировки я случайно смешал свои изменения с изменениями генератора.

В принципе, здесь я создаю библиотеку для возврата строго типизированных данных типа SlowInformation после случайной задержки (я даже протестировал ее! Я увлекся...)

Основной файл, на котором следует сосредоточиться, это slow-ass-api.ts.

Подключите библиотеку к нашему приложению Angular и выполните подключение (коммит)

После этого наше приложение будет отображать данные из slow-ass-api с задержкой.

Добавить наивный e2e-тест (коммит)

Этот коммит добавляет базовый тест e2e, который, к сожалению, довольно ненадежный. Из-за случайной задержки возврата данных тест иногда проходит, а иногда нет. Это можно продемонстрировать, ускорив разрешение API (зафиксировать)

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

Сделать тест менее глючным (коммит)

Здесь мы экспериментируем, заставляя наш тест ждать 10 секунд, чтобы убедиться, что все данные есть. Это работает очень хорошо!

Тем не менее, мы заставили наши тесты занимать больше времени, чем нужно, и, что особенно важно, если для разрешения API потребуется больше 10 секунд, наш тест снова завершится ошибкой. Возможно, это не лучшее решение в конце концов…

Усложнить приложение (коммит)

Мы получаем некоторые требования от нашего владельца продукта, и кажется, что требуется новая функция, где, если факт находится на уровне интереса holyCrudThatIsInteresting, мы должны поставить кнопку, позволяющую пользователю запрашивать дополнительную информацию о факте.

Мы добавляем эту функцию и стараемся обновить наши тесты e2e.

Теперь логика нашего приложения усложнилась, нам нужно учитывать эту сложность в наших тестах e2e.

Протестировать новое сложное приложение (коммит)

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

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

Введите stub slow information service (фиксация)

Мы создаем новый сервис, который реализует существующий InformationService в приложении Angular. Поскольку он строго типизирован, он должен следовать тому же интерфейсу, поэтому мы можем быть относительно уверены, что не сможем заставить какие-либо методы в нашей заглушке возвращать бессмысленные или недопустимые данные.

Этот коммит — основная часть этого поста. Здесь мы используем файлы окружения Angular, а также внедрение их зависимостей для запуска наших тестов e2e с StubSlowInformationService вместо SlowInformationService.

Теперь наши тесты запускаются, и запускаются быстро.

Если реализация медленного API изменится, наша заглушка перестанет компилироваться, и мы знаем, что нам нужно обновить наш код. Таким образом, этот подход относительно безопасен, предполагая, что у вас есть достаточно четко определенный контракт о том, как должен вести себя API (в данном случае наши определения типов TypeScript).

Ура!

Еще больше контроля (коммит)

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

Опять же, это относительно безопасно, если предприняты шаги, чтобы убедиться, что контракт API соблюдается в приложении Angular (при соблюдении типов, определенных в библиотеке slow-ass-api.

Вывод

Нам удалось написать тест e2e, который является достаточно надежным, быстрым и простым в управлении.

Из-за того, что и наше приложение Angular, и slow ass api соответствуют общему соглашению о поведении API, мы можем быть относительно уверены, что наши тесты имеют смысл и представляют собой реалистичное взаимодействие с нашим API.

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

Первоначально опубликовано на http://wtfisanapi.com 22 апреля 2019 г.