Тестирование компонент¶
Процесс тестирования Angular компонентов несколько отличается от тестирования сервисов и других сущностей, поскольку компонент — это результат взаимодействия класса и HTML-шаблона, что необходимо учитывать при тестировании.
Тест, проверяющий представление и класс, требует создания компонента в браузере, как в реально работающем приложении, что требует немного больших ресурсов.
Если вам необходимо убедиться в правильности описания логики класса, никак не влияющей на отображение, то отпадает необходимость определять компонент в структуре DOM.
Рассмотрим пример.
login-form.component.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 32 33 34 35 36 37 38 39 40 41 42 43 | |
login-form.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 32 33 34 | |
Если у компонента нет зависимостей, то экземпляр его класса в тесте создается с помощью ключевого слова new и без использования утилиты TestBed.
Первый тест проверяет установку значений формы в момент инициализации компонента, второй — возникновение события validate, инициируемое методом send().
Обратите внимание на то, как осуществляется проверка @Input() и @Output() свойств.
В процессе Angular component testing методы жизненного цикла не вызываются по умолчанию, как в реально работающем приложении. В тестах их вызов осуществляется явно.
Приступим к тестированию компонентов Angular с проверкой шаблона.
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 | |
Метод createComponent() создает указанный компонент в DOM-дереве тестовой среды и возвращает объект типа ComponentFixture, через который можно получить доступ к экземпляру компонента используя свойство componentInstance и убедиться в том, что компонент инициализирован в DOM.
1 | |
Другое полезное свойство объекта ComponentFixture — nativeElement. Значение свойства — объект типа HTMLElement. У объектов HTMLElement имеется метод querySelector, который по заданному селектору осуществляет поиск элементов в пределах шаблона компонента и также возвращает объект или массив объектов типа HTMLElement.
1 | |
Свойства объекта nativeElement напрямую зависят от среды выполнения теста. Например, вне браузера DOM-эмуляция просто невозможна, например, в приложении Angular Universal, именно поэтому имеется свойство debugElement с объектом типа DebugElement в качестве значения. В объекте также имеется объект nativeElement, который работает универсально независимо от платформы. Поэтому рекомендуется при написании тестов придерживаться следующего формата:
1 2 | |
Правда, если платформа не браузерная, то метод querySelector() не сработает. Аналогом являются query() и queryAll() объекта debugElement, принимающего результат, возвращаемый статическим методом css() класса By. Класс By входит в состав библиотеки @angular/platform-browser.
1 2 3 4 5 6 | |
By.css() принимает селектор в формате, аналогичному в querySelector().
В последних примерах проверялось статическое содержимое элементов HTML-разметки, т. е. текст присутствовал в шаблоне еще до компиляции компонента. Но при задании значения вот так
1 2 3 4 5 6 7 8 9 10 11 12 13 | |
тесты выполнились бы, поскольку createComponent() не связывает класс компонента с его шаблоном. Все переменные в таком случаем заменяются на пустые строки. Для инициации привязки необходимо вызвать detectChanges() у объекта, возвращаемого после вызова метода createComponent().
1 2 3 4 5 6 7 | |
Еще одна особенность приведенных ранее примеров — определение верстки в одном файле с определением класса. Но чаще всего (и это правильно) HTML-код и стили к нему выносятся в отдельные файлы. В таком случае необходимо вслед за методом configureTestingModule() вызвать compileComponents().
Принудительная компиляция необходима только если тестирование Angular компонентов выполняется вне среды CLI. В случае запуска через Angular CLI компиляция происходит автоматически.
1 2 3 4 5 6 7 8 9 10 11 | |
Асинхронный compileComponents() возвращает Promise и вызывается совместно с асинхронной функцией async() из библиотеки @angular/core/testing. Все синхронные операции после компиляции компонентов должны указываться в части then(), иначе будет сгенерировано исключение.
Вызов метода абсолютно безвреден. Обращение к compileComponents() без необходимости никак не повлияет на время и производительность тестирования.