Перейти к содержанию

API утилиты для тестирования

📅 28.02.2022

На этой странице описаны наиболее полезные функции тестирования Angular.

Утилиты тестирования Angular включают TestBed, ComponentFixture и несколько функций, которые управляют тестовой средой. Классы TestBed и ComponentFixture рассматриваются отдельно.

Вот краткое описание отдельных функций в порядке их вероятной полезности:

waitForAsync

Запускает тело функции test (it) или setup (beforeEach) в специальной async test zone. См. waitForAsync.

fakeAsync

Запускает тело теста (it) в специальной тестовой зоне fakeAsync, обеспечивая линейный стиль кодирования потока управления. См. fakeAsync.

tick

Имитирует течение времени и завершение ожидающих асинхронных действий путем промывки очередей таймера и микрозадачи в тестовой зоне fakeAsync.

Любознательному и увлеченному читателю может понравиться эта длинная запись в блоге "Задачи, микрозадачи, очереди и расписания".

Принимает необязательный аргумент, который переводит виртуальные часы вперед на указанное количество миллисекунд, очищая асинхронные действия, запланированные в этот промежуток времени. См. tick.

inject

Инжектирует одну или несколько служб из текущего инжектора TestBed в тестовую функцию. Он не может инжектировать сервис, предоставляемый самим компонентом. См. обсуждение debugElement.injector.

discardPeriodicTasks

Если тест fakeAsync() завершается с ожидающими выполнения задачами событий таймера (поставленные в очередь обратные вызовы setTimeOut и setInterval), тест завершается с явным сообщением об ошибке.

В целом, тест должен завершаться без очередей задач. Если ожидаются ожидающие выполнения задачи таймера, вызовите discardPeriodicTasks, чтобы очистить очередь задач и избежать ошибки.

flushMicrotasks

Если тест fakeAsync() завершается с нерешенными микрозадачами, такими как неразрешенные обещания, тест завершается с явным сообщением об ошибке.

В целом, тест должен ждать завершения микрозадач. Если ожидаются незавершенные микрозадачи, вызовите flushMicrotasks, чтобы очистить очередь микрозадач и избежать ошибки.

ComponentFixtureAutoDetect

Маркер поставщика для службы, которая включает автоматическое обнаружение изменений.

getTestBed

Получает текущий экземпляр TestBed. Обычно не требуется, поскольку обычно достаточно статических методов класса TestBed. Экземпляр TestBed раскрывает несколько редко используемых членов, которые недоступны как статические методы.

Краткое описание класса TestBed

Класс TestBed является одной из основных утилит тестирования Angular. Его API довольно большой и может быть подавляющим, пока вы не изучите его понемногу.

Прочитайте сначала начальную часть этого руководства, чтобы получить основы, прежде чем пытаться освоить весь API.

Определение модуля, передаваемое в configureTestingModule, является подмножеством свойств метаданных @NgModule.

1
2
3
4
5
6
type TestModuleMetadata = {
    providers?: any[],
    declarations?: any[],
    imports?: any[],
    schemas?: Array<SchemaMetadata | any[]>,
};

Каждый метод переопределения принимает MetadataOverride<T>, где T — это тип метаданных, соответствующий методу, то есть параметр @NgModule, @Component, @Directive или @Pipe.

1
2
3
4
5
type MetadataOverride<T> = {
    add?: Partial<T>,
    remove?: Partial<T>,
    set?: Partial<T>,
};

API TestBed состоит из статических методов класса, которые либо обновляют, либо ссылаются на глобальный экземпляр TestBed.

Внутри, все статические методы охватывают методы текущего экземпляра TestBed, который также возвращается функцией getTestBed().

Вызывайте методы TestBed в рамках beforeEach(), чтобы обеспечить новый старт перед каждым отдельным тестом.

Ниже приведены наиболее важные статические методы в порядке их вероятной полезности.

configureTestingModule

Шаймы тестирования (karma-test-shim, browser-test-shim) создают начальное тестовое окружение и модуль тестирования по умолчанию. Модуль тестирования по умолчанию сконфигурирован с базовыми декларациями и некоторыми заменителями сервисов Angular, которые необходимы каждому тестировщику.

Вызовите configureTestingModule, чтобы уточнить конфигурацию модуля тестирования для определенного набора тестов, добавляя и удаляя импорт, декларации (компонентов, директив и пайпов) и провайдеров.

compileComponents

Асинхронная компиляция модуля тестирования после завершения его конфигурирования. Вы должны вызвать этот метод, если любой из компонентов модуля тестирования имеет templateUrl или styleUrls, поскольку получение файлов шаблонов и стилей компонентов обязательно асинхронно. См. compileComponents.

После вызова compileComponents конфигурация TestBed замораживается на время работы текущего спецификатора.

createComponent<T>

Создает экземпляр компонента типа T на основе текущей конфигурации TestBed. После вызова createComponent конфигурация TestBed замораживается на время работы текущего образца.

overrideModule

Замена метаданных для заданного NgModule. Напомним, что модули могут импортировать другие модули. Метод overrideModule может проникнуть глубоко в текущий модуль тестирования, чтобы изменить один из этих внутренних модулей.

overrideComponent

Заменить метаданные для заданного класса компонента, который может быть глубоко вложен во внутренний модуль.

overrideDirective

Заменить метаданные для заданного класса директивы, который может быть глубоко вложен во внутренний модуль.

overridePipe

Заменить метаданные для заданного класса pipe, который может быть глубоко вложен во внутренний модуль.

inject {: #testbed-inject}

Получение сервиса из текущего инжектора TestBed. Функция inject часто подходит для этой цели. Но inject выбрасывает ошибку, если не может предоставить сервис.

Что если услуга необязательна?

Метод TestBed.inject() принимает необязательный второй параметр — объект, который нужно вернуть, если Angular не может найти провайдера (null в данном примере):

1
expect(TestBed.inject(NotProvided, null)).toBeNull();

После вызова TestBed.inject, конфигурация TestBed замораживается на время работы текущей спецификации.

initTestEnvironment {: #testbed-initTestEnvironment}

Инициализация тестовой среды для всего цикла тестирования.

Тестовые шимы (karma-test-shim, browser-test-shim) вызывают его за вас, поэтому вам редко придется вызывать его самостоятельно.

Вызовите этот метод только один раз. Чтобы изменить это значение по умолчанию в середине выполнения теста, сначала вызовите resetTestEnvironment.

Укажите фабрику компиляторов Angular, PlatformRef и модуль тестирования Angular по умолчанию. Альтернативы для небраузерных платформ доступны в общем виде @angular/platform-<platform_name>/testing/<platform_name>.

resetTestEnvironment

Сброс начального тестового окружения, включая модуль тестирования по умолчанию.

Несколько методов экземпляра TestBed не покрываются статическими методами класса TestBed. Они нужны редко.

Фикстура ComponentFixture

Функция TestBed.createComponent<T> создает экземпляр компонента T и возвращает сильно типизированную ComponentFixture для этого компонента.

Свойства и методы ComponentFixture предоставляют доступ к компоненту, его DOM-представлению и аспектам его Angular-окружения.

Свойства ComponentFixture

Вот наиболее важные свойства для тестировщиков, в порядке вероятной полезности.

componentInstance

Экземпляр класса компонента, созданный командой TestBed.createComponent.

debugElement

DebugElement, связанный с корневым элементом компонента.

DebugElement предоставляет представление о компоненте и его DOM-элементе во время тестирования и отладки. Это критически важное свойство для тестировщиков. Наиболее интересные члены описаны ниже.

nativeElement

Собственный элемент DOM в корне компонента.

changeDetectorRef

ChangeDetectorRef для компонента.

Значение ChangeDetectorRef наиболее ценно при тестировании компонента, который имеет метод ChangeDetectionStrategy.OnPush или обнаружение изменений компонента находится под вашим программным контролем.

Методы ComponentFixture

Методы fixture заставляют Angular выполнять определенные задачи на дереве компонентов. Вызывайте эти методы, чтобы вызвать поведение Angular в ответ на имитацию действий пользователя.

Вот наиболее полезные методы для тестировщиков.

detectChanges

Запустите цикл обнаружения изменений для компонента.

Вызовите его для инициализации компонента (он вызывает ngOnInit) и после вашего тестового кода измените значения свойств компонента, связанных с данными. Angular не видит, что вы изменили personComponent.name, и не будет обновлять привязку name, пока вы не вызовете detectChanges.

После этого выполните checkNoChanges, чтобы убедиться, что нет циклических обновлений, пока не будет вызвано detectChanges(false);

autoDetectChanges

Установите значение true, если вы хотите, чтобы приспособление автоматически обнаруживало изменения.

Когда параметр autodetect равен true, приспособление для тестирования вызывает detectChanges сразу после создания компонента. Затем он прослушивает соответствующие события зоны и вызывает detectChanges соответственно. Если ваш тестовый код изменяет значения свойств компонента напрямую, вам, вероятно, все равно придется вызывать fixture.detectChanges для запуска обновления привязки данных.

По умолчанию используется false. Тестировщики, предпочитающие тонкий контроль над поведением тестов, обычно оставляют значение false.

checkNoChanges

Выполните обнаружение изменений, чтобы убедиться, что нет никаких ожидающих изменений. Если они есть, бросает исключение.

isStable

Если приспособление в настоящее время стабильно, возвращается true. Если есть асинхронные задачи, которые не были завершены, возвращается false.

whenStable

Возвращает обещание, которое разрешается, когда приспособление становится стабильным.

Чтобы возобновить тестирование после завершения асинхронной активности или асинхронного обнаружения изменений, подключите это обещание. См. whenStable.

destroy

Запуск разрушения компонента.

DebugElement

Элемент DebugElement предоставляет важную информацию о DOM-представлении компонента.

Из DebugElement корневого компонента теста, возвращаемого fixture.debugElement, вы можете пройтись (и запросить) по всем поддеревьям элементов и компонентов компонента.

Вот наиболее полезные члены DebugElement для тестировщиков, в примерном порядке полезности:

nativeElement

Соответствующий элемент DOM в браузере

query

Вызов query(predicate: Predicate<DebugElement>) возвращает первый DebugElement, который соответствует predicate на любой глубине в поддереве.

queryAll

Вызов queryAll(predicate: Predicate<DebugElement>) возвращает все DebugElements, которые соответствуют predicate на любой глубине в поддереве.

injector

Инжектор зависимостей хоста. Например, инжектор экземпляра компонента корневого элемента.

componentInstance

Экземпляр собственного компонента элемента, если он есть.

context

Объект, обеспечивающий родительский контекст для этого элемента. Часто это экземпляр компонента-предка, который управляет этим элементом.

Когда элемент повторяется в *ngFor, контекст представляет собой NgForOf, свойство $implicit которого является значением экземпляра строки. Например, hero в *ngFor="let hero of heroes".

children

Непосредственные дочерние элементы DebugElement. Пройдитесь по дереву, спускаясь по детям.

DebugElement также имеет childNodes, список объектов DebugNode. DebugElement происходит от объектов DebugNode, и зачастую узлов больше, чем элементов. Тестировщики обычно могут игнорировать простые узлы.

parent

Родитель DebugElement. Null, если это корневой элемент.

name

Имя тега элемента, если это элемент.

triggerEventHandler

Запускает событие по его имени, если в коллекции listeners элемента есть соответствующий слушатель. Вторым параметром является объект события, ожидаемый обработчиком. См. triggerEventHandler.

Если у события нет слушателя или есть какая-то другая проблема, подумайте о вызове nativeElement.dispatchEvent(eventObject).

listeners

Обратные вызовы, присоединенные к свойствам @Output компонента и/или свойствам событий элемента.

providerTokens

Токены поиска инжектора этого компонента. Включает сам компонент плюс токены, которые компонент перечисляет в своих метаданных providers.

source

Где найти этот элемент в шаблоне исходного компонента.

references

Словарь объектов, связанных с локальными переменными шаблона (например, #foo), с ключом по имени локальной переменной.

Методы DebugElement.query(predicate) и DebugElement.queryAll(predicate) принимают предикат, который фильтрует поддерево исходного элемента на предмет соответствия DebugElement.

Предикат — это любой метод, который принимает DebugElement и возвращает истинное значение. Следующий пример находит все DebugElements со ссылкой на локальную переменную шаблона с именем "content":

1
2
3
4
// Filter for DebugElements with a #content reference
const contentRefs = el.queryAll(
    (de) => de.references['content']
);

Класс Angular By имеет три статических метода для общих предикатов:

Статический метод Подробности
By.all Возвращает все элементы
By.css(selector) Возвращает элементы с соответствующими CSS-селекторами
By.directive(directive) Возвращает элементы, которые Angular сопоставил с экземпляром класса директивы
1
2
3
4
5
// Can find DebugElement either by css selector or by directive
const h2 = fixture.debugElement.query(By.css('h2'));
const directive = fixture.debugElement.query(
    By.directive(HighlightDirective)
);

Комментарии