안정적인 소프트웨어는 철저한 테스트에서 시작됩니다. Jest/Vitest로 단위 테스트, Playwright로 E2E 테스트, Chrome DevTools로 효과적인 디버깅을 마스터하세요.
Reliable software starts with thorough testing. Master unit tests with Jest/Vitest, E2E tests with Playwright, and effective debugging with Chrome DevTools.
Vitest 단위 테스트 Vitest Unit Testing
Vitest는 Vite 기반의 빠른 테스트 러너입니다. Jest와 호환되는 API로 쉽게 마이그레이션할 수 있습니다.
Vitest is a fast test runner built on Vite. Easy migration with Jest-compatible API.
import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
globals: true,
environment: 'jsdom',
coverage: {
reporter: ['text', 'html'],
},
},
});
import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
globals: true,
environment: 'jsdom',
coverage: {
reporter: ['text', 'html'],
},
},
});
import { describe, it, expect } from 'vitest';
import { add, multiply } from './utils';
describe('Math Utils', () => {
it('두 숫자를 더한다', () => {
expect(add(1, 2)).toBe(3);
});
it('두 숫자를 곱한다', () => {
expect(multiply(3, 4)).toBe(12);
});
it('0을 곱하면 0이다', () => {
expect(multiply(5, 0)).toBe(0);
});
});
import { describe, it, expect } from 'vitest';
import { add, multiply } from './utils';
describe('Math Utils', () => {
it('adds two numbers', () => {
expect(add(1, 2)).toBe(3);
});
it('multiplies two numbers', () => {
expect(multiply(3, 4)).toBe(12);
});
it('returns 0 when multiplying by 0', () => {
expect(multiply(5, 0)).toBe(0);
});
});
Mock과 Spy Mocks and Spies
외부 의존성을 격리하여 테스트합니다. API 호출, 데이터베이스 등을 모킹합니다.
Isolate and test external dependencies. Mock API calls, databases, etc.
import { fetchUser } from './api';
// 모듈 전체 모킹
vi.mock('./api');
describe('User Service', () => {
beforeEach(() => {
vi.clearAllMocks();
});
it('사용자 정보를 가져온다', async () => {
// Mock 반환값 설정
vi.mocked(fetchUser).mockResolvedValue({
id: 1,
name: '홍길동'
});
const user = await fetchUser(1);
expect(user.name).toBe('홍길동');
expect(fetchUser).toHaveBeenCalledWith(1);
});
});
import { fetchUser } from './api';
// Mock entire module
vi.mock('./api');
describe('User Service', () => {
beforeEach(() => {
vi.clearAllMocks();
});
it('fetches user info', async () => {
// Set mock return value
vi.mocked(fetchUser).mockResolvedValue({
id: 1,
name: 'John Doe'
});
const user = await fetchUser(1);
expect(user.name).toBe('John Doe');
expect(fetchUser).toHaveBeenCalledWith(1);
});
});
Playwright E2E 테스트 Playwright E2E Testing
Playwright는 실제 브라우저에서 사용자 시나리오를 테스트합니다. 크로스 브라우저 테스트를 지원합니다.
Playwright tests user scenarios in real browsers. Supports cross-browser testing.
import { test, expect } from '@playwright/test';
test.describe('로그인 페이지', () => {
test('유효한 자격증명으로 로그인', async ({ page }) => {
// 페이지 이동
await page.goto('/login');
// 폼 입력
await page.fill('[data-testid="email"]', '[email protected]');
await page.fill('[data-testid="password"]', 'password123');
// 제출
await page.click('[data-testid="submit"]');
// 결과 검증
await expect(page).toHaveURL('/dashboard');
await expect(page.locator('h1')).toHaveText('대시보드');
});
test('잘못된 비밀번호로 에러 표시', async ({ page }) => {
await page.goto('/login');
await page.fill('[data-testid="email"]', '[email protected]');
await page.fill('[data-testid="password"]', 'wrong');
await page.click('[data-testid="submit"]');
await expect(page.locator('.error')).toBeVisible();
});
});
import { test, expect } from '@playwright/test';
test.describe('Login Page', () => {
test('login with valid credentials', async ({ page }) => {
// Navigate
await page.goto('/login');
// Fill form
await page.fill('[data-testid="email"]', '[email protected]');
await page.fill('[data-testid="password"]', 'password123');
// Submit
await page.click('[data-testid="submit"]');
// Verify result
await expect(page).toHaveURL('/dashboard');
await expect(page.locator('h1')).toHaveText('Dashboard');
});
test('shows error with wrong password', async ({ page }) => {
await page.goto('/login');
await page.fill('[data-testid="email"]', '[email protected]');
await page.fill('[data-testid="password"]', 'wrong');
await page.click('[data-testid="submit"]');
await expect(page.locator('.error')).toBeVisible();
});
});
Chrome DevTools 디버깅 Chrome DevTools Debugging
Chrome DevTools는 강력한 디버깅 도구입니다. 중단점, 콘솔, 네트워크 탭을 활용합니다.
Chrome DevTools is a powerful debugging tool. Utilize breakpoints, console, and network tab.
// 1. debugger 문으로 중단점 설정
function processData(data) {
debugger; // 여기서 실행 중단
return data.map(item => item * 2);
}
// 2. 조건부 로깅
console.log('%c중요!', 'color: red; font-size: 20px');
console.table(users); // 테이블 형태로 출력
console.group('API 호출');
console.log('요청:', request);
console.log('응답:', response);
console.groupEnd();
// 3. 성능 측정
console.time('fetch');
await fetchData();
console.timeEnd('fetch'); // fetch: 123ms
// 1. Set breakpoint with debugger statement
function processData(data) {
debugger; // Execution stops here
return data.map(item => item * 2);
}
// 2. Conditional logging
console.log('%cImportant!', 'color: red; font-size: 20px');
console.table(users); // Output as table
console.group('API Call');
console.log('Request:', request);
console.log('Response:', response);
console.groupEnd();
// 3. Performance measurement
console.time('fetch');
await fetchData();
console.timeEnd('fetch'); // fetch: 123ms
✨ 테스팅 Best Practices ✨ Testing Best Practices
- AAA 패턴: Arrange(준비), Act(실행), Assert(검증)
- 테스트 격리: 각 테스트가 독립적으로 실행
- 커버리지 목표: 중요 로직 80% 이상 커버
- E2E 최소화: 핵심 시나리오만 E2E로 테스트
- AAA Pattern: Arrange, Act, Assert
- Test Isolation: Each test runs independently
- Coverage Goal: 80%+ coverage for critical logic
- Minimize E2E: E2E only for critical scenarios
⚠️ 흔한 실수들 ⚠️ Common Mistakes
- 구현 세부사항 테스트 (내부 구조 의존)
- 너무 많은 Mock으로 실제 동작과 괴리
- 비동기 테스트에서
await누락 - 테스트 간 상태 공유로 인한 불안정
- Testing implementation details (internal structure dependency)
- Too many mocks diverging from real behavior
- Missing
awaitin async tests - Instability from shared state between tests
