출시·고도화 중
Angular 안내서 · 5/6
Angular 프로젝트에는 단위 테스트가 처음부터 설정되어 있고, 필요하면 CLI로 종단 간(e2e) 테스트 도구도 추가할 수 있습니다. 이 장에서는 테스트 실행, TestBed로 컴포넌트와 서비스 테스트하기, HTTP 모킹, 브라우저 수준의 e2e 테스트를 다룹니다.
테스트 파일은 대상 코드 옆에 두며 이름이 .spec.ts로 끝납니다. ng test는 angular.json의 test 타깃에 설정된 실행기로 테스트를 돌립니다.
ng test
ng test --watch=false
ng test --help어떤 실행기가 쓰이는지는 프로젝트를 언제 만들었는지에 따라 다릅니다. 최근 CLI는 새 프로젝트에 Vitest를 설정하고, 이전 버전으로 만든 프로젝트는 실제 브라우저에서 Karma와 Jasmine으로 테스트합니다. 둘 다 describe, it, beforeEach, expect 구조가 같고 Angular의 TestBed도 똑같이 동작하므로 아래 예제는 어느 쪽에서나 실행됩니다. 모킹 도구는 다릅니다. Jasmine은 jasmine.createSpy()와 spyOn()을, Vitest는 vi.fn()과 vi.spyOn()을 씁니다. 코드 커버리지 같은 옵션도 실행기마다 다르므로 ng test --help로 프로젝트에서 쓸 수 있는 옵션을 확인합니다.
TestBed는 테스트용 작은 Angular 환경을 만듭니다. 스탠드얼론 컴포넌트를 가져와 만들고, DOM을 조작한 뒤 결과를 확인합니다. 아래는 핵심 개념 장의 Counter 컴포넌트를 테스트하는 예입니다.
import { TestBed } from '@angular/core/testing';
import { Counter } from './counter';
describe('Counter', () => {
beforeEach(async () => {
await TestBed.configureTestingModule({ imports: [Counter] }).compileComponents();
});
it('starts at zero', () => {
const fixture = TestBed.createComponent(Counter);
fixture.detectChanges();
expect(fixture.nativeElement.textContent).toContain('0 x 2 = 0');
});
it('increments when the button is clicked', () => {
const fixture = TestBed.createComponent(Counter);
fixture.detectChanges();
const button: HTMLButtonElement = fixture.nativeElement.querySelector('button');
button.click();
fixture.detectChanges();
expect(fixture.nativeElement.textContent).toContain('1 x 2 = 2');
});
});fixture.detectChanges()는 변경 감지를 실행해 DOM에 최신 상태를 반영합니다. 컴포넌트가 비동기 작업을 기다린다면 await fixture.whenStable()로 대기 중인 작업이 끝날 때까지 기다립니다.
컴포넌트만 따로 떼어 테스트하려면 providers로 서비스의 가짜 구현을 넘깁니다. inject()도 같은 인젝터에서 값을 찾으므로 컴포넌트는 가짜 서비스를 받습니다.
import { TestBed } from '@angular/core/testing';
import { signal } from '@angular/core';
import { HeroList } from './hero-list';
import { HeroService } from './hero.service';
it('renders heroes from the service', async () => {
const fakeService = { all: signal([{ id: 1, name: 'Test Hero' }]), add: () => {} };
await TestBed.configureTestingModule({
imports: [HeroList],
providers: [{ provide: HeroService, useValue: fakeService }],
}).compileComponents();
const fixture = TestBed.createComponent(HeroList);
fixture.detectChanges();
expect(fixture.nativeElement.textContent).toContain('Test Hero');
});provideHttpClientTesting()은 실제 백엔드 대신 HttpTestingController를 넣어, 테스트가 나가는 요청을 살펴보고 직접 응답할 수 있게 합니다. provideHttpClient() 다음에 등록합니다.
import { TestBed } from '@angular/core/testing';
import { provideHttpClient } from '@angular/common/http';
import { HttpTestingController, provideHttpClientTesting } from '@angular/common/http/testing';
import { Todo, TodoApi } from './todo-api';
describe('TodoApi', () => {
let api: TodoApi;
let http: HttpTestingController;
beforeEach(() => {
TestBed.configureTestingModule({
providers: [provideHttpClient(), provideHttpClientTesting()],
});
api = TestBed.inject(TodoApi);
http = TestBed.inject(HttpTestingController);
});
afterEach(() => http.verify());
it('requests a limited list', () => {
let result: Todo[] = [];
api.list(2).subscribe((todos) => (result = todos));
const req = http.expectOne((r) => r.url.endsWith('/todos'));
expect(req.request.method).toBe('GET');
expect(req.request.params.get('_limit')).toBe('2');
req.flush([{ id: 1, title: 'Write tests', completed: false }]);
expect(result.length).toBe(1);
});
});http.verify()는 요청이 나갔는데 응답하지 않은 것이 남아 있으면 테스트를 실패시킵니다.
새 프로젝트에는 e2e 도구가 들어 있지 않습니다. e2e 타깃이 없는 프로젝트에서 ng e2e를 실행하면 도구를 추가하겠냐고 묻는데, Playwright, Cypress, WebdriverIO, Nightwatch, Puppeteer 등에서 고를 수 있습니다. 도구를 직접 설치해도 됩니다. Playwright라면 다음과 같습니다.
npm init playwright@latest
npx playwright testplaywright.config.ts에서 개발 서버를 지정하면 테스트 전에 앱을 먼저 띄웁니다.
import { defineConfig } from '@playwright/test';
export default defineConfig({
use: { baseURL: 'http://localhost:4200' },
webServer: {
command: 'npm start',
url: 'http://localhost:4200',
reuseExistingServer: !process.env['CI'],
},
});import { expect, test } from '@playwright/test';
test('home page greets the user', async ({ page }) => {
await page.goto('/');
await expect(page.getByRole('heading', { level: 1 })).toContainText('Hello');
});ng test는 프로젝트에 설정된 실행기로 .spec.ts 파일을 실행합니다. 최근 프로젝트는 Vitest, 이전 프로젝트는 Karma와 Jasmine입니다.TestBed로 컴포넌트와 서비스를 만들고, detectChanges()로 DOM을 갱신합니다.providers로 바꿔 끼우고, HTTP는 provideHttpClientTesting()으로 테스트합니다.ng e2e로 추가하거나 Playwright, Cypress 같은 도구를 직접 설치해 씁니다.
댓글 0개
로그인 · 로그인하면 댓글을 남길 수 있습니다.
첫 댓글을 남겨 보세요.