Тестирование сервисов¶
28.02.2022
Чтобы проверить, что ваши сервисы работают так, как вы задумали, вы можете написать тесты специально для них.
Если вы хотите поэкспериментировать с приложением, которое описано в этом руководстве, запустите его в браузере или скачайте и запустите его локально.
Сервисы часто являются самыми гладкими файлами для модульного тестирования. Вот несколько синхронных и асинхронных модульных тестов ValueService
, написанных без помощи утилит тестирования Angular.
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 |
|
Сервисы с зависимостями¶
Сервисы часто зависят от других сервисов, которые Angular инжектирует в конструктор. Во многих случаях вы можете создать и инжектировать эти зависимости вручную при вызове конструктора сервиса.
Простым примером является MasterService
:
1 2 3 4 5 6 7 |
|
MasterService
делегирует свой единственный метод, getValue
, инжектированному ValueService
.
Вот несколько способов проверить это.
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 44 45 46 47 48 49 50 51 52 |
|
Первый тест создает ValueService
с new
и передает его в конструктор MasterService
.
Однако инжектирование реального сервиса редко работает хорошо, поскольку большинство зависимых сервисов сложно создавать и контролировать.
Вместо этого высмеивайте зависимость, используйте фиктивное значение или создайте spy на соответствующем методе сервиса.
Note
Предпочитает шпионов, так как они, как правило, лучший способ поиздеваться над службами.
Эти стандартные методы тестирования отлично подходят для модульного тестирования сервисов в изоляции.
Однако вы почти всегда внедряете сервисы в классы приложения, используя инъекцию зависимостей Angular, и у вас должны быть тесты, отражающие эту модель использования. Утилиты тестирования Angular позволяют легко исследовать поведение внедренных сервисов.
Тестирование сервисов с помощью TestBed
.¶
Ваше приложение полагается на Angular dependency injection (DI) для создания сервисов. Когда у сервиса есть зависимый сервис, DI находит или создает этот зависимый сервис.
А если у этого зависимого сервиса есть свои собственные зависимости, DI находит или создает и их.
Как потребитель сервиса, вы не беспокоитесь ни о чем из этого. Вас не волнует порядок аргументов конструктора или то, как они создаются.
Как тестер сервисов, вы должны, по крайней мере, думать о первом уровне зависимостей сервисов, но вы можете позволить Angular DI сделать создание сервиса и разобраться с порядком аргументов конструктора, если используете утилиту тестирования TestBed
для предоставления и создания сервисов.
Angular TestBed
¶
TestBed
является наиболее важной из утилит тестирования Angular. В TestBed
создается динамически конструируемый модуль Angular test, который эмулирует модуль Angular @NgModule.
Метод TestBed.configureTestingModule()
принимает объект метаданных, который может иметь большинство свойств @NgModule.
Чтобы протестировать сервис, вы задаете свойство метаданных providers
с массивом сервисов, которые вы будете тестировать или имитировать.
1 2 3 4 5 6 7 |
|
Затем внедрите его внутрь теста, вызвав TestBed.inject()
с классом сервиса в качестве аргумента.
Функция TestBed.get()
была устаревшей начиная с версии 9 Angular. Чтобы свести к минимуму взлом изменений, Angular вводит новую функцию TestBed.inject()
, которую вы должны использовать вместо нее.
Информацию об удалении TestBed.get()
можно найти в Deprecations index.
1 2 3 4 |
|
Или внутри beforeEach()
, если вы предпочитаете инжектировать сервис как часть вашей установки.
1 2 3 4 5 6 |
|
При тестировании сервиса с зависимостью, предоставьте макет в массиве providers
.
В следующем примере имитатором является объект spy
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
Тест потребляет этого шпиона тем же способом, что и ранее.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
Тестирование без beforeEach()
¶
Большинство тестовых наборов в этом руководстве вызывают beforeEach()
для установки предварительных условий для каждого теста it()
и полагаются на TestBed
для создания классов и внедрения сервисов.
Существует и другая школа тестирования, которая никогда не вызывает beforeEach()
и предпочитает создавать классы явно, а не использовать TestBed
.
Вот как можно переписать один из тестов MasterService
в этом стиле.
Начните с размещения повторно используемого, подготовительного кода в функции setup вместо beforeEach()
.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
Функция setup()
возвращает литерал объекта с переменными, такими как masterService
, на которые может ссылаться тест. Вы не определяете полуглобальные переменные (например, let masterService: MasterService
) в теле describe()
.
Затем каждый тест вызывает setup()
в своей первой строке, прежде чем продолжить шаги, которые манипулируют объектом тестирования и утверждают ожидания.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
Обратите внимание, как тест использует деструктурирующее назначение для извлечения необходимых ему переменных настройки.
1 2 3 4 5 |
|
Многие разработчики считают этот подход более чистым и явным, чем традиционный стиль beforeEach()
.
Хотя это руководство по тестированию следует традиционному стилю, и по умолчанию CLI схемы генерируют тестовые файлы с beforeEach()
и TestBed
, не стесняйтесь использовать этот альтернативный подход в ваших собственных проектах.
Тестирование HTTP-сервисов¶
Сервисы данных, выполняющие HTTP-вызовы к удаленным серверам, обычно инжектируют и делегируют службу Angular HttpClient
для XHR-вызовов.
Вы можете протестировать сервис данных с инжектированным HttpClient
шпионом, как вы тестировали бы любой сервис с зависимостью.
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 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
|
Методы HeroService
возвращают Observables
. Вы должны подписаться на наблюдаемую переменную, чтобы (a) вызвать ее выполнение и (b) подтвердить успех или неудачу метода.
Метод subscribe()
принимает обратный вызов успеха (next
) и отказа (error
). Убедитесь, что вы предоставили обои обратные вызовы, чтобы перехватить ошибки.
Пренебрежение этим приводит к асинхронной не пойманной наблюдаемой ошибке, которую программа запуска тестов, скорее всего, отнесет к совершенно другому тесту.
HttpClientTestingModule
¶
Расширенные взаимодействия между сервисом данных и HttpClient
могут быть сложными и их трудно имитировать с помощью шпионов.
Модуль HttpClientTestingModule
может сделать эти сценарии тестирования более управляемыми.
Хотя пример кода, сопровождающий данное руководство, демонстрирует HttpClientTestingModule
, эта страница отсылает к Http guide, где подробно рассматривается тестирование с помощью HttpClientTestingModule
.