Примеры тестирования компонент¶
Компонент с вызовом асинхронного метода¶
Практически в каждом приложении имеются компоненты, которые зависимы от сервисов, которые хранят асинхронные методы, инициирующие 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 |
|