Основы тестирования
Тест — это код, который проверяет другой код: создаёт сервис или компонент, выполняет действие и сравнивает результат с ожидаемым. Тесты запускаются за секунды и сразу показывают, если изменение что-то сломало. Для каждого файла, созданного ng generate, CLI уже сделал заготовку теста с окончанием .spec.ts.
Запуск
ng testКоманда собирает тесты и запускает их, а после каждого сохранения — заново. В Angular 20 по умолчанию используются Karma и Jasmine, тесты выполняются в браузере. В Angular 21 и новее новые проекты используют Vitest. Функции describe, it, expect в простых тестах выглядят одинаково.
Тест сервиса
Откройте src/app/todo-store.spec.ts и опишите поведение хранилища задач:
// src/app/todo-store.spec.ts
import { TestBed } from '@angular/core/testing';
import { TodoStore } from './todo-store';
describe('TodoStore', () => {
let store: TodoStore;
beforeEach(() => {
store = TestBed.inject(TodoStore);
});
it('добавляет задачу', () => {
store.add('Купить хлеб');
expect(store.todos().length).toBe(1);
expect(store.todos()[0].title).toBe('Купить хлеб');
});
it('считает невыполненные задачи', () => {
store.add('Первая');
store.add('Вторая');
store.toggle(store.todos()[0].id);
expect(store.left()).toBe(1);
});
});describe объединяет тесты, it — один тест, expect(...).toBe(...) — проверка. TestBed — тестовое окружение Angular, его метод inject() выдаёт сервис так же, как inject() в компоненте. Для каждого теста создаётся новое окружение, поэтому задачи из первого теста не попадают во второй.
В терминале появится отчёт: зелёным отмечаются пройденные тесты, красным — упавшие, с ожидаемым и полученным значением.
Тест компонента
Компонент создают методом TestBed.createComponent() и проверяют получившийся HTML:
// src/app/todo-item/todo-item.spec.ts
import { TestBed } from '@angular/core/testing';
import { TodoItem } from './todo-item';
describe('TodoItem', () => {
it('выводит название задачи', () => {
TestBed.configureTestingModule({ imports: [TodoItem] });
const fixture = TestBed.createComponent(TodoItem);
fixture.componentRef.setInput('todo', { id: 1, title: 'Позвонить Олегу', done: false });
fixture.detectChanges();
const el: HTMLElement = fixture.nativeElement;
expect(el.textContent).toContain('Позвонить Олегу');
});
});setInput() задаёт входное свойство, как это сделал бы родитель. detectChanges() просит Angular обновить шаблон, а nativeElement — корневой элемент компонента, в котором можно искать текст и теги.
Что проверять
| Что | Пример проверки |
|---|---|
| Логика сервиса | После add() в списке на одну задачу больше |
| Вычисления | left() считает только невыполненные |
| Вывод компонента | Название задачи есть в HTML |
| События | После щелчка по флажку сработал выход toggle |
Начните с сервисов: в них больше всего логики, а тестировать их проще всего.
Частая ошибка
Забыть fixture.detectChanges() после setInput() или изменения данных. Шаблон останется в прежнем состоянии, и проверка текста упадёт, хотя компонент работает правильно. После каждого изменения данных в тесте компонента вызывайте detectChanges().