Это продолжение Тестирования угловых компонентов с мелкой визуализацией

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

Рендеринг без HTML-шаблона

В первоначальном выпуске shallow-render вы могли протестировать свои компоненты, набрав тот же HTML-код, что и в вашем шаблоне. Это может быть хорошим примером того, как использовать компонент в ваших спецификациях:

Вы можете видеть, что когда вам понадобятся более продвинутые привязки, мы имитируем модель шаблона / контроллера в нашем тесте, указав шаблон HTML для визуализации вместе с переменными области видимости в объекте bind, переданном в средство визуализации.

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

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

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

Плюсы:

  • Меньше кода! (не нужно указывать привязки событий)
  • Требует, чтобы свойства привязки соответствовали именам со свойствами компонента, что может помочь избежать путаницы имени привязки со свойством компонента.

Минусы:

  • Иногда желательно иметь HTML-код в вашей спецификации в качестве примера, чтобы другие разработчики могли сразу увидеть его использование.
  • Не поддерживает отображение проецируемого содержимого или директив.

Директивы по тестированию

Директивы в Angular очень похожи на компоненты; настолько, что они часто упоминаются как одно и то же в кодовой базе Angular. Shallow довольно легко поддерживает директивы тестирования.

Обратите внимание: поскольку директивы должны быть прикреплены к существующему элементу HTML, вы должны указать шаблон HTML для средства визуализации. Также обратите внимание, что element, возвращаемый при рендеринге, - это div, к которому директива была прикреплена в HTML.

Использование сменных модулей

Распространенным шаблоном в сообществе Angular является предоставление тестового модуля, который представляет собой замену модулю, разработанному специально для тестов. Angular делает это довольно часто, вот HttpClientTestingModule, который используется для замены фиктивного запросчика для экземпляров HttpClient.

Мы можем использовать их в наших тестах, «заменив» исходный модуль тестовым модулем.

shallow.replaceModule(HttpClientModule, HttpClientTestingModule)

Вот пример теста с использованием модуля тестирования:

Здесь много чего происходит. Большая часть сложности здесь связана с тем, что тестирование HttpClient запросов в Angular немного многословно. Вот несколько примечаний (в том порядке, в котором вы их прочтете из теста).

  • В наших тестах мы используем fakeAsync и async. fakeAsync позволяет нам вручную управлять потоком цепочек обещаний в нашем компоненте.
  • Мы используем метод shallow get для извлечения инъекций из модуля. (мы также должны использовать HttpTestingController, потому что Angular использовал абстрактный класс).
  • Мы устанавливаем наши HttpClient mocks, а затем tick. Это разрешает цепочку обещаний запроса в конструкторе компонента, который, в свою очередь, обновляет свойство labelText компонента.
  • Поскольку мы инициировали изменение пользовательского интерфейса, мы должны detectChanges, прежде чем делать утверждения для компонента.

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

Тестирование с помощью RouterModule

Тестирование приложений, использующих модуль Angular Routing, является горячей темой в списке проблем с мелкой отрисовкой. С некоторыми из недавних дополнений в shallow-render теперь все довольно просто. Здесь мы снова обнаруживаем, что Angular предоставил нам тестовый модуль для маршрутизации (RouterTestingModule). Нам просто нужно заменить исходный RouterModule тестовой версией и убедиться, что наш тестовый модуль настроен в соответствии с документацией Angular.

Это простейшая форма тестирования маршрутов. Вы даже можете поставить RouterTestingModule замену глобально, используя alwaysReplaceModule, так что вам не нужно помнить о замене в каждой спецификации.

Использование селекторов ViewChild / ContentChild

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

Поскольку shallow автоматически имитирует компонент list-item в наших тестах, нам нужно имитировать функцию ListItemComponent activate, чтобы мы могли убедиться, что она вызывается для первого элемента в списке. Здесь нам пришлось использовать стиль рендеринга HTML Template, чтобы мы могли рендерить дочерние компоненты в наш ListContainer компонент.

Дополнительное примечание об изоляции в модульных тестах

Обратите внимание: поскольку это тест для ListItemContainer, нам все равно, что метод ListItem#activate делает сListItem, потому что тесты для этого ListItem поведения должны входить в тесты для ListItem. Следуя этой модели изоляции тестируемого компонента, мы гарантируем, что мы сможем реорганизовать поведение активации ListItem без ненужного нарушения тестов для ListItemContainer. Нет ничего более неприятного, чем рефакторинг внутреннего устройства одного компонента с обратной совместимостью и нарушение модульных тестов для некоторых других компонентов, которые на самом деле не сломались!