Тестирование сервисов¶
Начнем с изучения тестирования сервисов Angular, поскольку именно сервисы проще всего покрываются тестами.
Ключевую роль в тестировании Angular приложений играет утилита TestBed
из библиотеки @angular/core/testing
. Она позволяет эмулировать модуль Testing Module, подобный модулю, создаваемого с декоратором @NgModule()
. Тестовый модуль необходим для определения модулей, сервисов, компонентов и т. д., от которых зависим тест.
В TestBed
имеется метод configureTestingModule()
, которая принимает объект конфигурации аналогичный тому, что передается @NgModule()
.
1 2 3 4 5 |
|
В коде выше определенный в providers
тестового модуля сервис AppService
становится доступным для использования каждому из выполняемых тестов. Получение экземпляра сервиса осуществляется методом get()
утилиты TestBed
.
get()
может предоставить только те сервисы, которые указаны в свойстве providers
модуля Testing Module.
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 |
|
Разберем пример. Здесь описан один тест, который проверяет корректность работы метода getData()
сервиса AppService
. Метод getData()
принимает число и возвращает его удвоенное значение.
Для сбора информации о вызовах метода getData()
используется spyOn()
.
Обычно сервис не ограничивается только собственными методами. В сложном приложении сервисы взаимодействуют между собой, используя функционал друг друга.
В таких случаях общепринято использовать объекты Spy
, чтобы не создавать ради одного или нескольких методов полноценный экземпляр еще одного сервиса.
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 |
|
В примере createSpyObj()
эмулирует сервис AppService
с его единственным методом getData()
.
Если все тесты работают с одним набором данных, которые должен возвращать метод getData()
, то в beforeEach()
задать эти данные можно так:
1 2 3 |
|
Инструменты также предусматривают возможность тестирования сервисов Angular, которые обращаются за данными к удаленному серверу. Ключевую роль здесь играют модуль HttpTestingModule
и контроллер HttpTestingController
.
Тестирование HTTP-сервисов не подразумевает обращение к удаленному API. Вместо этого все исходящие запросы перенаправляются в контроллер HttpTestingController
.
app.service.ts
1 2 3 4 5 6 7 8 9 10 11 |
|
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 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
|
Как видно из примера, доступ к объекту запроса осуществляется с использованием метода expectOne()
экземпляра класса HttpTestingController
, идентифицирующего запрос в зависимости от переданного ему условия. Метод принимает параметром URL, на который осуществляется запрос, либо сам объект запроса. Например, можно отловить запрос с наличием определенного HTTP-заголовка или с определенным его значением.
Условию должен удовлетворять только один запрос. Если таких запросов будет несколько или они будут отсутствовать вовсе, будет сгенерировано исключение. Для работы с группой запросов необходимо использовать метод match()
, который возвращает массив HTTP-запросов, попадающих под заданный критерий.
1 |
|
В приведенном коде переменная req
будет содержать массив всех запросов, сделанных на URL /api/data
.
Возвращаемые в ответ на запрос данные передаются аргументом методу flush()
.
В конце каждого такого теста у экземпляра класса HttpTestingController
нужно вызывать метод verify()
, который подтверждает, что все запросы в рамках текущего теста были выполнены. Код идеально подходит для размещения в функции afterEach()
.
Для эмуляции ответа сервера с кодом ошибки, вторым аргументом методу flush()
передается объект, где указывается статус и текст ошибки.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
|
Для ошибки сетевого уровня можно использовать метода error()
объекта запроса. Передаваемый параметр — объект типа ErrorEvent
.
1 2 3 4 5 |
|
В приведенных примерах fail()
используется для принудительного завершения выполнения теста с ошибкой в тех местах, где Angular не сможет самостоятельно определить, правильно ли был выполнен сценарий.