текст перекладу
Вступ:
У попередній частині ми розглянули труднощі, з якими стикаються розробники інтерфейсів, а також рішення цих проблем, дізналися про конфігурацію Karma, охоплення тестів та як тестувати локально. У цій частині ми глибше зануримося у написання юніт-тестів для Angular у різних сценаріях.
Щодо юніт-тестування Angular, генерація звітів про покриття коду у форматі LCOV та створення звітів у текстовому або HTML форматах після виконання тестів є звичайними практиками. Ось загальний посібник, як досягти цього:
Генерація звітів LCOV (покриття рядків):
- Налаштування тестового середовища: Переконайтесь, що ваш проект Angular налаштований для юніт-тестування. Зазвичай це включає встановлення необхідних залежностей та налаштування тестового середовища.
- Запуск тестів з покриттям коду: Використовуйте вбудовані інструменти тестування Angular, такі як Karma разом з Istanbul, для запуску юніт-тестів з увімкненим покриттям коду. Зазвичай для цього достатньо виконати команду:
ng test --code-coverage
- Генерація звіту LCOV: Після запуску тестів Istanbul генерує звіти про покриття в різних форматах, зокрема LCOV. Зазвичай звіт LCOV можна знайти в директорії coverage вашого проекту Angular.
Генерація текстових або HTML звітів:
1. Використання Karma HTML Reporter (для HTML звітів):
Ви можете скористатися плагіном HTML Reporter для Karma, щоб генерувати HTML звіти для результатів ваших тестів. Спочатку встановіть Karma HTML Reporter:
npm install karma-html-reporter - save-dev
2. Налаштування Karma для використання HTML Reporter:
Оновіть конфігураційний файл Karma (karma.conf.js) для використання HTML reporter. Додайте або оновіть масив reporters:
reporters: ['progress', 'html'],
- Генерація текстових звітів:
Щоб згенерувати текстові звіти, ви можете налаштувати формат виводу вашого тестового запуску. Наприклад, за замовчуванням Karma може виводити результати тестів у текстовому форматі в консоль.
module.exports = function(config) {
config.set({
frameworks: ['jasmine', '@angular-devkit/build-angular'],
// Додати плагіни
plugins: [
require('karma-jasmine'),
require('karma-chrome-launcher'),
require('@angular-devkit/build-angular/plugins/karma'),
require('karma-html-reporter')
],
// Конфігурація репортерів
reporters: ['progress', 'html'],
htmlReporter: {
outputFile: 'test-results.html' // Файл для виведення HTML звіту
},
// Інші налаштування...
});
};
Як написати юніт-тест в Angular?
Пакет тестування Angular включає два основних утиліт: TestBed і async.
TestBed — надає реальне середовище виконання (функціональні вимоги та операційна поведінка), з яким ми можемо тестувати компоненти.
Корисні методи TestBed:
· configureTestingModule — використовується для налаштування тестового модуля Angular.
· createComponent — використовується для створення екземпляра самого компонента.
· compiledComponents — використовується для компіляції компонентів.
Коли ми пишемо юніт-тести, Angular рекомендує використовувати процес —
AAA: Arrange, Act, Assert
- Arrange — Ми повинні підготувати всі вимоги, необхідні для тестування модуля.
- Act — Після підготовки ми залучаємо фактичну логіку до підготовлених даних.
3.
текст перекладу
Assert — ми вже виконали дію, тепер час перевірити результати тесту.
Давайте розглянемо дуже простий приклад коду, метод findAreaOfRectangle в AppComponent:
findAreaOfRectangle(length:number,width:number):number{
return length * width;
};
import { TestBed } from '@angular/core/testing';
import { AppComponent } from './app.component';
describe('AppComponent', () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [
AppComponent
],
}).compileComponents();
});
it("should test findAreaOfRectangle - length, width",()=>{
// Arrange
let length = 10;
let width = 5;
// Act
let area = findAreaOfRectangle(length,width);
//Assert
expect(area).toBe(50);
});
});
Корисні методи jasmine-
· describe (description, function) — використовується для групування набору тестів
· beforeEach (function)- використовується для виконання задач перед кожним юніт-тестом
· afterEach (function)- використовується для виконання задач після кожного юніт-тесту
· It (description, function) — використовується для виконання тесту
· expect(value)- використовується для визначення результату тесту
· toBe(value)- використовується для вказівки очікуваного значення тесту
· toEqual(object)- цей метод перевіряє, чи результат є тим самим об'єктом, що й зазначене значення.
· toMatch(regexp)- цей метод перевіряє, чи результат відповідає зазначеному регулярному виразу.
· toBeUndefined () — цей метод перевіряє, чи результат не визначений
· toBeNull()- цей метод перевіряє, чи результат є null
· toBeTruthy () — цей метод перевіряє, чи результат є істинним
· toBeFalsy () — цей метод перевіряє, чи результат є хибним
· toContain(substring)- цей метод перевіряє, чи результат містить зазначену підстрічку
Корисні методи ComponentFixture-
· componentInstance — повертає об'єкт компонента
· debugElement- повертає тестовий елемент хоста для компонента
· nativeElement- повертає DOM-об'єкт, який представляє елемент хоста для компонента
· detectChanges () — використовується для виявлення змін стану в шаблоні компонента
Корисні методи DebugElement-
· nativeElement — повертає об'єкт, що представляє HTML елемент в DOM
· children- повертає масив об'єктів DebugElement
· query(selectorFunction)- повертає перший DebugElement, для якого функція повертає true
· queryAll (selectorFunction) — повертає всі об'єкти DebugElement, для яких функція повертає true
Створимо простий компонент Angular для відображення даних про продукт, а потім напишемо юніт-тест для нього, використовуючи моки для імітації даних відповіді.
По-перше, створимо компонент для відображення даних про продукт:
import { Component, OnInit } from '@angular/core';
import { ProductService } from './product.service';
@Component({
selector: 'app-product',
template: `
{{ product.name }}
Price: {{ product.price }}
` }) export class ProductComponent implements OnInit { product: any; constructor(private productService: ProductService) { } ngOnInit(): void { this.productService.getProduct().subscribe((product: any) => { this.product = product; }); } } ``` ``` // product.service.ts import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class ProductService { constructor(private http: HttpClient) { } getProduct(): Observable { return this.http.get('/api/product'); } } ``` Тепер напишемо юніт-тест для ProductComponent, використовуючи моки для імітації даних відповіді:
``` // product.component.spec.ts import { ComponentFixture, TestBed } from '@angular/core/testing'; import { HttpClientTestingModule } from '@angular/common/http/testing'; import { of } from 'rxjs'; import { ProductComponent } from './product.component';
текст перекладу
import { ProductService } from './product.service';
describe('ProductComponent', () => {
let component: ProductComponent;
let fixture: ComponentFixture;
let productService: ProductService;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ProductComponent],
imports: [HttpClientTestingModule],
providers: [ProductService]
}).compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(ProductComponent);
component = fixture.componentInstance;
productService = TestBed.inject(ProductService);
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
it('should display product data', () => {
const mockProduct = { name: 'Test Product', price: 10.99 };
spyOn(productService, 'getProduct').and.returnValue(of(mockProduct));
fixture.detectChanges();
const compiled = fixture.nativeElement;
expect(compiled.querySelector('h2').textContent).toContain('Test Product');
expect(compiled.querySelector('p').textContent).toContain('Price: 10.99');
});
});
У цьому тесті ми використовуємо HttpClientTestingModule — в тестах ми вже здійснили підслуховування всього методу ProductService, тому цей модуль лише підключено для надання залежності для HTTP клієнта, який використовується всередині ProductService під час тестування.
текст перекладу
Ми потім симулюємо відповідь, повертаючи Observable з тестовими даними продукту за допомогою of
. Нарешті, ми перевіряємо, чи правильно компонент відображає дані продукту.
Підсумок:
У цій частині серії тестів для Angular ми детально розглянули, як генерувати LCOV звіти, текстові/HTML звіти, а також написали наш перший тестовий випадок і зрозуміли основи та передові методи написання тестів.
Перекладено з: Mastering Angular Testing Framework — Writing your first unit test case — PART 2