Loading...
Loading...
Compare original and translation side by side
/\
/E2E\ ← 적음 (느림, 비용 높음)
/______\
/ \
/Integration\ ← 중간
/____________\
/ \
/ Unit Tests \ ← 많음 (빠름, 비용 낮음)
/________________\ /\
/E2E\ ← 少量(速度慢、成本高)
/______\
/ \
/Integration\ ← 中等数量
/____________\
/ \
/ Unit Tests \ ← 大量(速度快、成本低)
/________________\describe('calculateDiscount', () => {
it('should apply 10% discount for orders over $100', () => {
// Given: 주어진 상황
const order = { total: 150, customerId: '123' };
// When: 행동을 실행
const discount = calculateDiscount(order);
// Then: 결과 검증
expect(discount).toBe(15);
});
it('should not apply discount for orders under $100', () => {
const order = { total: 50, customerId: '123' };
const discount = calculateDiscount(order);
expect(discount).toBe(0);
});
it('should throw error for invalid order', () => {
const order = { total: -10, customerId: '123' };
expect(() => calculateDiscount(order)).toThrow('Invalid order');
});
});// 외부 의존성 모킹
jest.mock('../services/emailService');
import { sendEmail } from '../services/emailService';
describe('UserService', () => {
it('should send welcome email on registration', async () => {
// Arrange
const mockSendEmail = sendEmail as jest.MockedFunction<typeof sendEmail>;
mockSendEmail.mockResolvedValueOnce(true);
// Act
await userService.register({ email: 'test@example.com', password: 'pass' });
// Assert
expect(mockSendEmail).toHaveBeenCalledWith({
to: 'test@example.com',
subject: 'Welcome!',
body: expect.any(String)
});
});
});describe('calculateDiscount', () => {
it('should apply 10% discount for orders over $100', () => {
// Given: 给定场景
const order = { total: 150, customerId: '123' };
// When: 执行操作
const discount = calculateDiscount(order);
// Then: 验证结果
expect(discount).toBe(15);
});
it('should not apply discount for orders under $100', () => {
const order = { total: 50, customerId: '123' };
const discount = calculateDiscount(order);
expect(discount).toBe(0);
});
it('should throw error for invalid order', () => {
const order = { total: -10, customerId: '123' };
expect(() => calculateDiscount(order)).toThrow('Invalid order');
});
});// 模拟外部依赖
jest.mock('../services/emailService');
import { sendEmail } from '../services/emailService';
describe('UserService', () => {
it('should send welcome email on registration', async () => {
// Arrange
const mockSendEmail = sendEmail as jest.MockedFunction<typeof sendEmail>;
mockSendEmail.mockResolvedValueOnce(true);
// Act
await userService.register({ email: 'test@example.com', password: 'pass' });
// Assert
expect(mockSendEmail).toHaveBeenCalledWith({
to: 'test@example.com',
subject: 'Welcome!',
body: expect.any(String)
});
});
});describe('POST /api/users', () => {
beforeEach(async () => {
await db.user.deleteMany(); // Clean DB
});
it('should create user with valid data', async () => {
const response = await request(app)
.post('/api/users')
.send({
email: 'test@example.com',
username: 'testuser',
password: 'Password123!'
});
expect(response.status).toBe(201);
expect(response.body.user).toMatchObject({
email: 'test@example.com',
username: 'testuser'
});
// DB에 실제로 저장되었는지 확인
const user = await db.user.findUnique({ where: { email: 'test@example.com' } });
expect(user).toBeTruthy();
});
it('should reject duplicate email', async () => {
// 첫 번째 사용자 생성
await request(app)
.post('/api/users')
.send({ email: 'test@example.com', username: 'user1', password: 'Pass123!' });
// 중복 시도
const response = await request(app)
.post('/api/users')
.send({ email: 'test@example.com', username: 'user2', password: 'Pass123!' });
expect(response.status).toBe(409);
});
});describe('POST /api/users', () => {
beforeEach(async () => {
await db.user.deleteMany(); // 清理数据库
});
it('should create user with valid data', async () => {
const response = await request(app)
.post('/api/users')
.send({
email: 'test@example.com',
username: 'testuser',
password: 'Password123!'
});
expect(response.status).toBe(201);
expect(response.body.user).toMatchObject({
email: 'test@example.com',
username: 'testuser'
});
// 验证是否实际保存到数据库
const user = await db.user.findUnique({ where: { email: 'test@example.com' } });
expect(user).toBeTruthy();
});
it('should reject duplicate email', async () => {
// 创建第一个用户
await request(app)
.post('/api/users')
.send({ email: 'test@example.com', username: 'user1', password: 'Pass123!' });
// 尝试创建重复用户
const response = await request(app)
.post('/api/users')
.send({ email: 'test@example.com', username: 'user2', password: 'Pass123!' });
expect(response.status).toBe(409);
});
});import { test, expect } from '@playwright/test';
test.describe('User Registration Flow', () => {
test('should complete full registration process', async ({ page }) => {
// 1. 홈페이지 방문
await page.goto('http://localhost:3000');
// 2. 회원가입 버튼 클릭
await page.click('text=Sign Up');
// 3. 폼 작성
await page.fill('input[name="email"]', 'test@example.com');
await page.fill('input[name="username"]', 'testuser');
await page.fill('input[name="password"]', 'Password123!');
// 4. 제출
await page.click('button[type="submit"]');
// 5. 성공 메시지 확인
await expect(page.locator('text=Welcome')).toBeVisible();
// 6. 대시보드로 리다이렉트 확인
await expect(page).toHaveURL('http://localhost:3000/dashboard');
// 7. 사용자 정보 표시 확인
await expect(page.locator('text=testuser')).toBeVisible();
});
test('should show error for invalid email', async ({ page }) => {
await page.goto('http://localhost:3000/signup');
await page.fill('input[name="email"]', 'invalid-email');
await page.fill('input[name="password"]', 'Password123!');
await page.click('button[type="submit"]');
await expect(page.locator('text=Invalid email')).toBeVisible();
});
});import { test, expect } from '@playwright/test';
test.describe('User Registration Flow', () => {
test('should complete full registration process', async ({ page }) => {
// 1. 访问首页
await page.goto('http://localhost:3000');
// 2. 点击注册按钮
await page.click('text=Sign Up');
// 3. 填写表单
await page.fill('input[name="email"]', 'test@example.com');
await page.fill('input[name="username"]', 'testuser');
await page.fill('input[name="password"]', 'Password123!');
// 4. 提交表单
await page.click('button[type="submit"]');
// 5. 验证成功消息
await expect(page.locator('text=Welcome')).toBeVisible();
// 6. 验证重定向到仪表盘
await expect(page).toHaveURL('http://localhost:3000/dashboard');
// 7. 验证用户信息显示
await expect(page.locator('text=testuser')).toBeVisible();
});
test('should show error for invalid email', async ({ page }) => {
await page.goto('http://localhost:3000/signup');
await page.fill('input[name="email"]', 'invalid-email');
await page.fill('input[name="password"]', 'Password123!');
await page.click('button[type="submit"]');
await expect(page.locator('text=Invalid email')).toBeVisible();
});
});// 1. RED: 실패하는 테스트 작성
describe('isPalindrome', () => {
it('should return true for palindrome', () => {
expect(isPalindrome('racecar')).toBe(true);
});
});
// 2. GREEN: 테스트 통과하는 최소 코드
function isPalindrome(str: string): boolean {
return str === str.split('').reverse().join('');
}
// 3. REFACTOR: 코드 개선
function isPalindrome(str: string): boolean {
const cleaned = str.toLowerCase().replace(/[^a-z0-9]/g, '');
return cleaned === cleaned.split('').reverse().join('');
}
// 4. 추가 테스트 케이스
it('should ignore case and spaces', () => {
expect(isPalindrome('A man a plan a canal Panama')).toBe(true);
});
it('should return false for non-palindrome', () => {
expect(isPalindrome('hello')).toBe(false);
});// 1. RED:编写失败的测试
describe('isPalindrome', () => {
it('should return true for palindrome', () => {
expect(isPalindrome('racecar')).toBe(true);
});
});
// 2. GREEN:编写让测试通过的最简代码
function isPalindrome(str: string): boolean {
return str === str.split('').reverse().join('');
}
// 3. REFACTOR:优化代码
function isPalindrome(str: string): boolean {
const cleaned = str.toLowerCase().replace(/[^a-z0-9]/g, '');
return cleaned === cleaned.split('').reverse().join('');
}
// 4. 添加更多测试用例
it('should ignore case and spaces', () => {
expect(isPalindrome('A man a plan a canal Panama')).toBe(true);
});
it('should return false for non-palindrome', () => {
expect(isPalindrome('hello')).toBe(false);
});undefinedundefinedundefinedundefined#testing#test-strategy#TDD#unit-test#integration-test#E2E#code-quality#testing#test-strategy#TDD#unit-test#integration-test#E2E#code-quality