Примеры тестирования компонент¶
Компонент с вызовом асинхронного метода¶
Практически в каждом приложении имеются компоненты, которые зависимы от сервисов, которые хранят асинхронные методы, инициирующие HTTP-запросы к удаленному серверу и возвращающие определенные данные.
Поскольку основное назначение unit-тестов проверка не работоспособности API, а результата преобразования и (или) отображения полученных данных, то вызовы этих методов и их данных эмулируются через константы или Spy объекты.
info-message.component.ts
1 2 3 4 5 6 7 8 9 10 11 | |
info-message.component.spec.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | |
Не используйте реальные сервисы в тестах компонентов. Их внедрение может оказаться крайне сложным, или вообще невозможным, поскольку в сервисах могут быть проверки, которые пройдут только в реально работающем приложении.
В приведенном примере Angular тестирования константа appService предоставляет все необходимые данные и методы для их преобразования подобно тому, как это делает реальный сервис.
Для эмуляции асинхронных методов сервисов лучше подойдут Spy объекты.
app.service.ts
1 2 3 4 5 6 7 8 | |
app.service.spec.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | |
Объект Spy позволяет эмулировать обращение к асинхронному методу (название). Но сам тест выполняется синхронно, внутри него не выполняется никаких асинхронных действий.
При использовании в тестах Angular компонентов сервисов следует помнить, что Angular имеет иерархическое построение injector-ов. Так, если сервис был определен на уровне компонента, то при тестировании он должен быть взят не из корневого injector-а, а из injector-а самого компонента.
1 | |
Но если сервис определен именно в модуле, т. е. находится в корневом injector-е, то можно использовать более простой в восприятии способ получения сервиса с использованием TestBed.get().
1 | |
Для асинхронности теста используйте функцию fakeAsync() библиотеки @angular/core/testing.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | |
Важным здесь является функция tick(), без которой использование fakeAsync() было бы бессмысленным. В качестве аргумента она принимает количество миллисекунд, на которое выполнение теста приостановиться. Так, в примере дальнейшие операции в тесте зависимы от вызова асинхронного метода (название), который выполняется за 180 миллисекунд.
Но данный подход не подойдет, если вы не знаете точное время исполнения метода. Самый простой пример — обращение к удаленному API, где время исполнения зависит от множества неконтролируемых факторов: стабильность соединения, пропускная способность канала, нагрузка на сервер и т. д. Здесь необходимо использовать функцию async().
info-message.component.ts
1 2 3 4 5 6 7 | |
info-message.component.spec.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | |
async() запускает тест в специальной среде исполнения. Но главное здесь — метод whenSable(), возвращающий объект Promise, который выполнится после того, как очередь задач JavaScript станет пустой, т. е. будут исполнены все асинхронные и синхронные действия. Здесь отпадает необходимость в знании точного времени исполнения.
Взаимодействие компонентов¶
Когда вы передаете данные из одного компонента в другой через @Output() свойство, вам понадобится в тесте получить доступ к двум компонентам одновременно. Пример тестирования для такого случая.
parent.component.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | |
child.component.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | |
parent.component.spec.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | |
Основное внимание здесь нужно сосредоточить на блоке beforeEach(). При конфигурации модуля TestingModule в части providers необходимо указать все компоненты, к которым происходит обращение в процессе тестирования. При этом явно создается именно экземпляр класса того компонента, который является родительским ко всем другим.
Доступ к дочерним компонентам осуществляется с помощью селекторов, применяемых относительно свойства nativeElement объекта debugElement с использованием функции querySelector(). В качестве селектора следует использовать id-атрибуты или классы, которые однозначно идентифицируют нужный компонент. Метод detectChanges() вызывается для привязки переданных значений в HTML-шаблоне.
Задать значения свойств дочернего компонента без явного создания экземпляра класса не получится.
Организация кода¶
Даже при тестировании небольшого компонента часто приходится производить много манипуляций с его свойствами или осуществлять выборку HTML-элементов по селекторам в пределах шаблона.
Поэтому для упрощения Angular тестирования и концентрации в одном месте методов, реализующих наиболее часто используемый функционал, общепринято создавать вспомогательный класс Page.
page.class.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | |
При написании сценариев тестирования экземпляр класса Page создается в блоке beforeEach().
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | |