Claude Code를 사용한 코드 테스트 및 품질
테스트는 유지 관리 가능한 프로젝트의 기초입니다. 그것은 단순한 안전망이 아니다 버그에 반대할 뿐만 아니라 실행 가능한 문서 코드가 어떻게 작동하는지 설명합니다. 행동해야 한다. Claude Code는 테스트 작성 속도를 획기적으로 향상시킬 수 있습니다. TDD에서 안내식 리팩토링까지, 지원 디버깅부터 엣지 케이스 적용까지.
이 기사에서는 Claude Code를 각 수준에서 활용하는 방법을 살펴보겠습니다. 테스트 피라미드, 구체적인 프롬프트, 실제 사례 및 모범 사례 포함 강력하고 유지 관리 가능한 테스트를 얻으려면
시리즈 개요
| # | Articolo | 집중하다 |
|---|---|---|
| 1 | 클로드 코드 소개 | 설정 및 첫 번째 단계 |
| 2 | 개념 및 요구사항 | 아이디어에서 사양까지 |
| 3 | 코드베이스 아키텍처 | 프로젝트 구조 |
| 4 | 컨텍스트 및 CLAUDE.md | 고급 구성 |
| 5 | 코드의 구조 | 구현 안내 |
| 6 | 신속한 엔지니어링 | 고급 프롬프트 |
| 7 | 현재 위치 - 테스트 및 품질 | 테스트 및 디버깅 |
| 8 | 선적 서류 비치 | README 및 API 문서 |
| 9 | 배포 및 DevOps | CI/CD 및 도커 |
| 10 | 프로젝트 진화 | 유지 |
테스트 피라미드
테스트 피라미드는 속도 균형을 위한 최적의 전략을 정의합니다. 적용 범위 및 유지 관리 가능성. Claude Code는 모든 수준에서 당신을 도울 수 있습니다.
테스트 피라미드
/\
/ \
/ E2E\ Pochi (5-10%)
/------\ Lenti, costosi, fragili
/ \ Testano flussi utente completi
/Integration\ Moderati (15-25%)
/--------------\ Velocita media
/ \ Testano interazioni tra componenti
/ Unit Tests \ Molti (70-80%)
/--------------------\ Veloci, isolati, stabili
/ \ Testano singole unita
/________________________\
레벨별 기능
| 수준 | 속도 | 격리 | 비용 | 신뢰 |
|---|---|---|---|---|
| 단위 | ~1ms | 높은 | 베이스 | 내부 논리 |
| 완성 | ~100ms | 중간 | 중간 | 상호작용 |
| E2E | ~5초 | 베이스 | 높은 | 완벽한 시스템 |
Claude Code를 사용한 테스트 전략
Claude Code는 기존 코드에서 완전한 테스트를 생성하는 데 탁월합니다. 최적의 전략은 다음과 같습니다.
권장되는 작업 흐름
| 단계 | 행동 | 클로드 코드 |
|---|---|---|
| 1 | 테스트할 코드 분석 | "이 기능에는 어떤 테스트 케이스가 필요합니까?" |
| 2 | 행복한 경로에 대한 테스트 생성 | "성공 사례에 대한 단위 테스트 생성" |
| 3 | 극단적인 경우 추가 | "최첨단 사례 및 오류에 대한 테스트 추가" |
| 4 | 검토 및 리팩터링 | "이러한 테스트를 검토하고 가독성을 향상시키세요." |
| 5 | 적용 범위 확인 | “어떤 라인이 다루어지지 않습니까?” |
단위 테스트 생성
단위 테스트는 개별 기능이나 클래스를 완전히 격리하여 테스트합니다. 빠르고 안정적이며 개발 중에 즉각적인 피드백을 제공합니다.
단위 테스트 생성 프롬프트
Generate comprehensive unit tests for this service:
```typescript
[PASTE SERVICE CODE HERE]
```
TESTING REQUIREMENTS:
- Framework: Jest with TypeScript
- Coverage target: >90% for this critical service
- Mock ALL external dependencies (repositories, external services)
TEST CATEGORIES TO COVER:
1. Happy Path: Normal successful operations
2. Validation: Invalid inputs, edge cases
3. Error Handling: Expected errors are thrown correctly
4. Edge Cases: Empty arrays, null values, boundary conditions
5. State Changes: Verify side effects (calls to dependencies)
OUTPUT FORMAT:
- Complete test file with all imports
- Use describe/it blocks with clear descriptions
- Include beforeEach for setup
- Group tests by method
- Use AAA pattern (Arrange, Act, Assert)
- Add comments explaining non-obvious test cases
NAMING CONVENTION:
- Describe: "ServiceName"
- Nested describe: "methodName"
- It: "should [expected behavior] when [condition]"
전체 예: UserService 단위 테스트
import {{ '{' }} UserService {{ '}' }} from './user.service';
import {{ '{' }} UserRepository {{ '}' }} from './user.repository';
import {{ '{' }} EmailService {{ '}' }} from '@shared/services/email.service';
import {{ '{' }} ValidationError, NotFoundError, ConflictError {{ '}' }} from '@shared/errors';
import {{ '{' }} createUserFixture, validUserDto {{ '}' }} from './fixtures/user.fixtures';
describe('UserService', () => {{ '{' }}
let service: UserService;
let mockUserRepository: jest.Mocked<UserRepository>;
let mockEmailService: jest.Mocked<EmailService>;
beforeEach(() => {{ '{' }}
// Create fresh mocks for each test
mockUserRepository = {{ '{' }}
findById: jest.fn(),
findByEmail: jest.fn(),
create: jest.fn(),
update: jest.fn(),
softDelete: jest.fn(),
findAll: jest.fn(),
{{ '}' }} as any;
mockEmailService = {{ '{' }}
sendWelcomeEmail: jest.fn(),
sendPasswordResetEmail: jest.fn(),
{{ '}' }} as any;
service = new UserService(mockUserRepository, mockEmailService);
{{ '}' }});
afterEach(() => {{ '{' }}
jest.clearAllMocks();
{{ '}' }});
// ================================================
// CREATE USER
// ================================================
describe('createUser', () => {{ '{' }}
describe('happy path', () => {{ '{' }}
it('should create user and send welcome email when valid data provided', async () => {{ '{' }}
// Arrange
const dto = validUserDto;
const expectedUser = createUserFixture({{ '{' }} id: 'user-123', ...dto {{ '}' }});
mockUserRepository.findByEmail.mockResolvedValue(null);
mockUserRepository.create.mockResolvedValue(expectedUser);
mockEmailService.sendWelcomeEmail.mockResolvedValue(undefined);
// Act
const result = await service.createUser(dto);
// Assert
expect(result.id).toBe('user-123');
expect(result.email).toBe(dto.email);
expect(mockUserRepository.create).toHaveBeenCalledWith(
expect.objectContaining({{ '{' }}
name: dto.name,
email: dto.email,
{{ '}' }})
);
expect(mockEmailService.sendWelcomeEmail).toHaveBeenCalledWith(
expectedUser.email,
expectedUser.name
);
{{ '}' }});
{{ '}' }});
describe('validation errors', () => {{ '{' }}
it('should throw ConflictError when email already exists', async () => {{ '{' }}
// Arrange
const existingUser = createUserFixture({{ '{' }} email: 'exists@test.com' {{ '}' }});
mockUserRepository.findByEmail.mockResolvedValue(existingUser);
// Act & Assert
await expect(
service.createUser({{ '{' }} ...validUserDto, email: 'exists@test.com' {{ '}' }})
).rejects.toThrow(ConflictError);
expect(mockUserRepository.create).not.toHaveBeenCalled();
expect(mockEmailService.sendWelcomeEmail).not.toHaveBeenCalled();
{{ '}' }});
it('should throw ValidationError when password is too weak', async () => {{ '{' }}
// Arrange
mockUserRepository.findByEmail.mockResolvedValue(null);
// Act & Assert
await expect(
service.createUser({{ '{' }} ...validUserDto, password: '123' {{ '}' }})
).rejects.toThrow(ValidationError);
{{ '}' }});
{{ '}' }});
describe('edge cases', () => {{ '{' }}
it('should trim whitespace from email', async () => {{ '{' }}
// Arrange
mockUserRepository.findByEmail.mockResolvedValue(null);
mockUserRepository.create.mockResolvedValue(createUserFixture());
// Act
await service.createUser({{ '{' }}
...validUserDto,
email: ' user@test.com '
{{ '}' }});
// Assert
expect(mockUserRepository.findByEmail).toHaveBeenCalledWith('user@test.com');
{{ '}' }});
it('should normalize email to lowercase', async () => {{ '{' }}
// Arrange
mockUserRepository.findByEmail.mockResolvedValue(null);
mockUserRepository.create.mockResolvedValue(createUserFixture());
// Act
await service.createUser({{ '{' }}
...validUserDto,
email: 'User@TEST.com'
{{ '}' }});
// Assert
expect(mockUserRepository.findByEmail).toHaveBeenCalledWith('user@test.com');
{{ '}' }});
{{ '}' }});
{{ '}' }});
// ================================================
// GET USER BY ID
// ================================================
describe('getUserById', () => {{ '{' }}
it('should return user when found', async () => {{ '{' }}
// Arrange
const user = createUserFixture({{ '{' }} id: 'user-123' {{ '}' }});
mockUserRepository.findById.mockResolvedValue(user);
// Act
const result = await service.getUserById('user-123');
// Assert
expect(result).toEqual(user);
expect(mockUserRepository.findById).toHaveBeenCalledWith('user-123');
{{ '}' }});
it('should throw NotFoundError when user does not exist', async () => {{ '{' }}
// Arrange
mockUserRepository.findById.mockResolvedValue(null);
// Act & Assert
await expect(service.getUserById('non-existent'))
.rejects.toThrow(NotFoundError);
{{ '}' }});
it('should throw ValidationError when id is empty', async () => {{ '{' }}
await expect(service.getUserById('')).rejects.toThrow(ValidationError);
{{ '}' }});
{{ '}' }});
{{ '}' }});
통합 테스트
통합 테스트는 구성 요소가 함께 올바르게 작동하는지 확인합니다. 라우팅, 미들웨어, 검증 및 데이터베이스 액세스를 포함한 전체 API를 테스트합니다.
통합 테스트 프롬프트
Generate integration tests for this API:
ENDPOINTS:
- POST /api/users - Create user (requires auth)
- GET /api/users/:id - Get user by ID
- PATCH /api/users/:id - Update user (owner only)
- DELETE /api/users/:id - Soft delete (admin only)
TESTING REQUIREMENTS:
- Framework: Jest + Supertest
- Database: Test PostgreSQL (use transactions, rollback after each test)
- Auth: JWT tokens (mock or real test tokens)
TEST SCENARIOS FOR EACH ENDPOINT:
1. Success case with valid request
2. Validation errors (400) - invalid body, missing fields
3. Authentication errors (401) - missing/invalid token
4. Authorization errors (403) - wrong role/permissions
5. Not found errors (404) - resource doesn't exist
6. Conflict errors (409) - duplicate resources
SETUP/TEARDOWN:
- beforeAll: Create test database, run migrations
- beforeEach: Start transaction
- afterEach: Rollback transaction
- afterAll: Close database connection
Include helper functions for:
- Creating authenticated requests
- Generating test users
- Cleaning up test data
통합 테스트 예시
import request from 'supertest';
import {{ '{' }} app {{ '}' }} from '../app';
import {{ '{' }} db {{ '}' }} from '../database';
import {{ '{' }} createTestUser, getAuthToken, cleanupTestData {{ '}' }} from './helpers';
import {{ '{' }} UserRole {{ '}' }} from '@shared/types';
describe('Users API Integration Tests', () => {{ '{' }}
let adminToken: string;
let userToken: string;
let testUserId: string;
beforeAll(async () => {{ '{' }}
await db.connect();
await db.migrate();
// Create test users and get tokens
const admin = await createTestUser({{ '{' }} role: UserRole.ADMIN {{ '}' }});
const user = await createTestUser({{ '{' }} role: UserRole.USER {{ '}' }});
adminToken = await getAuthToken(admin);
userToken = await getAuthToken(user);
testUserId = user.id;
{{ '}' }});
afterAll(async () => {{ '{' }}
await cleanupTestData();
await db.disconnect();
{{ '}' }});
// ================================================
// POST /api/users - Create User
// ================================================
describe('POST /api/users', () => {{ '{' }}
const validPayload = {{ '{' }}
name: 'Integration Test User',
email: 'integration@test.com',
password: 'SecurePass123!',
{{ '}' }};
describe('success cases', () => {{ '{' }}
it('should create user with valid data (201)', async () => {{ '{' }}
const response = await request(app)
.post('/api/users')
.set('Authorization', `Bearer ${{ '{' }}adminToken{{ '}' }}`)
.send({{ '{' }} ...validPayload, email: `unique-${{ '{' }}Date.now(){{ '}' }}@test.com` {{ '}' }});
expect(response.status).toBe(201);
expect(response.body.data).toMatchObject({{ '{' }}
name: validPayload.name,
email: expect.stringContaining('@test.com'),
{{ '}' }});
expect(response.body.data.password).toBeUndefined();
expect(response.body.data.id).toBeDefined();
{{ '}' }});
{{ '}' }});
describe('validation errors (400)', () => {{ '{' }}
it('should return 400 when email is invalid', async () => {{ '{' }}
const response = await request(app)
.post('/api/users')
.set('Authorization', `Bearer ${{ '{' }}adminToken{{ '}' }}`)
.send({{ '{' }} ...validPayload, email: 'not-an-email' {{ '}' }});
expect(response.status).toBe(400);
expect(response.body.error.code).toBe('VALIDATION_ERROR');
{{ '}' }});
{{ '}' }});
describe('authentication errors (401)', () => {{ '{' }}
it('should return 401 without auth token', async () => {{ '{' }}
const response = await request(app)
.post('/api/users')
.send(validPayload);
expect(response.status).toBe(401);
expect(response.body.error.code).toBe('UNAUTHORIZED');
{{ '}' }});
{{ '}' }});
describe('authorization errors (403)', () => {{ '{' }}
it('should return 403 when non-admin tries to create user', async () => {{ '{' }}
const response = await request(app)
.post('/api/users')
.set('Authorization', `Bearer ${{ '{' }}userToken{{ '}' }}`)
.send(validPayload);
expect(response.status).toBe(403);
expect(response.body.error.code).toBe('FORBIDDEN');
{{ '}' }});
{{ '}' }});
{{ '}' }});
// ================================================
// DELETE /api/users/:id - Soft Delete (Admin Only)
// ================================================
describe('DELETE /api/users/:id', () => {{ '{' }}
it('should soft delete user when admin (204)', async () => {{ '{' }}
const userToDelete = await createTestUser();
const response = await request(app)
.delete(`/api/users/${{ '{' }}userToDelete.id{{ '}' }}`)
.set('Authorization', `Bearer ${{ '{' }}adminToken{{ '}' }}`);
expect(response.status).toBe(204);
// Verify user is soft deleted
const getResponse = await request(app)
.get(`/api/users/${{ '{' }}userToDelete.id{{ '}' }}`)
.set('Authorization', `Bearer ${{ '{' }}adminToken{{ '}' }}`);
expect(getResponse.status).toBe(404);
{{ '}' }});
it('should return 403 when non-admin tries to delete', async () => {{ '{' }}
const response = await request(app)
.delete(`/api/users/${{ '{' }}testUserId{{ '}' }}`)
.set('Authorization', `Bearer ${{ '{' }}userToken{{ '}' }}`);
expect(response.status).toBe(403);
{{ '}' }});
{{ '}' }});
{{ '}' }});
Claude Code로 안내되는 리팩터링
Claude Code는 동작을 유지하면서 리팩토링을 제안할 수 있습니다. 기존 테스트는 안전망이 됩니다.
I want to refactor this code. I have tests that cover its behavior:
CURRENT CODE:
```typescript
[PASTE CODE]
```
EXISTING TESTS (passing):
```typescript
[PASTE TESTS]
```
REFACTORING GOALS:
1. Reduce cyclomatic complexity
2. Extract reusable functions
3. Improve naming
CONSTRAINTS:
- All existing tests MUST still pass
- Don't change public interface
- No new dependencies
Provide:
1. Refactored code
2. Explanation of each change
3. Any new tests needed for extracted functions
Claude 코드를 사용한 디버깅 지원
Claude Code는 오류를 분석하고 근본 원인을 찾는 데 탁월합니다.
This test is failing and I can't figure out why:
TEST:
```typescript
it('should apply discount to order total', async () => {{ '{' }}
const order = await orderService.createOrder({{ '{' }}
items: [{{ '{' }} productId: 'prod-1', quantity: 2 {{ '}' }}],
couponCode: 'SAVE10',
{{ '}' }});
expect(order.total).toBe(90); // Expected $90 after 10% discount
expect(order.discount).toBe(10);
{{ '}' }});
```
ERROR:
```
Expected: 90
Received: 100
```
IMPLEMENTATION:
```typescript
async createOrder(dto: CreateOrderDto): Promise<Order> {{ '{' }}
const items = await this.getOrderItems(dto.items);
const subtotal = items.reduce((sum, item) => sum + item.price * item.quantity, 0);
let discount = 0;
if (dto.couponCode) {{ '{' }}
const coupon = await this.couponRepository.findByCode(dto.couponCode);
if (coupon) {{ '{' }}
discount = subtotal * (coupon.percentage / 100);
{{ '}' }}
{{ '}' }}
return this.orderRepository.create({{ '{' }}
items,
subtotal,
discount,
total: subtotal - discount,
{{ '}' }});
{{ '}' }}
```
Help me:
1. Identify why the test is failing
2. Determine if it's a test bug or implementation bug
3. Provide the fix
Claude Code와 함께하는 코드 검토
Claude Code를 사용하여 테스트 자체의 코드 검토를 수행합니다.
Review these tests for quality and completeness:
```typescript
[PASTE TESTS]
```
ANALYZE:
1. Test Coverage Gaps
- Missing happy paths
- Missing error scenarios
- Missing edge cases
2. Test Quality Issues
- Tests that test implementation vs behavior
- Flaky test patterns
- Poor isolation (shared state)
- Missing assertions
3. Maintainability Issues
- Unclear test names
- Code duplication
- Missing comments for complex scenarios
4. Best Practices Violations
- Not using AAA pattern
- Multiple assertions testing different things
- Mocking too much or too little
For each issue provide:
- Location (line/describe block)
- Problem description
- Recommended fix with code example
테스트 설비 및 공장
잘 구조화된 픽스처는 테스트를 더 읽기 쉽고 유지 관리하기 쉽게 만듭니다.
// fixtures/user.fixtures.ts
import {{ '{' }} User, UserRole, UserStatus {{ '}' }} from '@/entities/user.entity';
import {{ '{' }} CreateUserDto {{ '}' }} from '@/dto/create-user.dto';
// ================================================
// BASE FIXTURES - Valid default values
// ================================================
export const validUserDto: CreateUserDto = {{ '{' }}
name: 'Test User',
email: 'test@example.com',
password: 'SecurePassword123!',
{{ '}' }};
export const validUser: Partial<User> = {{ '{' }}
id: 'user-123',
name: 'Test User',
email: 'test@example.com',
role: UserRole.USER,
status: UserStatus.ACTIVE,
createdAt: new Date('2025-01-01'),
updatedAt: new Date('2025-01-01'),
{{ '}' }};
// ================================================
// FACTORY FUNCTION - Create users with overrides
// ================================================
let userCounter = 0;
export function createUserFixture(overrides: Partial<User> = {{ '{' }}{{ '}' }}): User {{ '{' }}
userCounter++;
return {{ '{' }}
id: `user-${{ '{' }}userCounter{{ '}' }}`,
name: 'Test User',
email: `test-${{ '{' }}userCounter{{ '}' }}@example.com`,
password: '$2b$10$hashedpassword',
role: UserRole.USER,
status: UserStatus.ACTIVE,
createdAt: new Date(),
updatedAt: new Date(),
deletedAt: null,
...overrides,
{{ '}' }} as User;
{{ '}' }}
// ================================================
// INVALID FIXTURES - For testing validation
// ================================================
export const invalidUserDtos = {{ '{' }}
missingName: {{ '{' }}
email: 'test@example.com',
password: 'SecurePassword123!',
{{ '}' }},
invalidEmail: {{ '{' }}
name: 'Test User',
email: 'not-an-email',
password: 'SecurePassword123!',
{{ '}' }},
weakPassword: {{ '{' }}
name: 'Test User',
email: 'test@example.com',
password: '123',
{{ '}' }},
{{ '}' }};
// ================================================
// SCENARIO FIXTURES - Specific test scenarios
// ================================================
export const userScenarios = {{ '{' }}
admin: () => createUserFixture({{ '{' }} role: UserRole.ADMIN {{ '}' }}),
inactive: () => createUserFixture({{ '{' }} status: UserStatus.INACTIVE {{ '}' }}),
deleted: () => createUserFixture({{ '{' }}
status: UserStatus.DELETED,
deletedAt: new Date(),
{{ '}' }}),
{{ '}' }};
// ================================================
// HELPERS
// ================================================
export function resetUserFixtures(): void {{ '{' }}
userCounter = 0;
{{ '}' }}
Claude Code를 사용한 TDD 워크플로
테스트 중심 개발은 Claude Code를 사용하면 더욱 효과적으로 작동합니다. 먼저 테스트를 작성한 다음 Claude가 구현을 제안하도록 하세요.
클로드 코드를 사용한 TDD
| 단계 | Tu | 클로드 코드 |
|---|---|---|
| 1. 레드 | 실패한 테스트 작성 | 테스트 케이스 제안 |
| 2.그린 | 구현을 요청하세요 | 최소한의 코드 생성 |
| 3. 리팩터링 | 개선을 요청하세요 | 리팩토링을 제안합니다 |
| 4.반복 | 새 테스트 추가 | 극단적인 경우를 제안합니다 |
I'm following TDD. Here's my failing test:
```typescript
describe('calculateDiscount', () => {{ '{' }}
it('should apply 10% discount for orders over $100', () => {{ '{' }}
expect(calculateDiscount(150)).toBe(15);
{{ '}' }});
it('should apply 20% discount for orders over $500', () => {{ '{' }}
expect(calculateDiscount(600)).toBe(120);
{{ '}' }});
it('should return 0 for orders under $100', () => {{ '{' }}
expect(calculateDiscount(50)).toBe(0);
{{ '}' }});
{{ '}' }});
```
1. Implement the MINIMUM code to make these tests pass
2. Don't add features not covered by tests
3. After implementation, suggest additional edge cases I should test
테스트 범위 및 격차 분석
Claude Code를 사용하여 발견되지 않은 코드를 식별하고 누락된 테스트를 생성하세요.
My coverage report shows uncovered lines:
FILE: src/services/order.service.ts
UNCOVERED LINES: 45-52, 78-85, 120-135
Here's the code at those lines:
```typescript
// Lines 45-52
if (order.status === 'cancelled') {{ '{' }}
throw new ValidationError('Cannot modify cancelled order');
{{ '}' }}
// Lines 78-85
if (items.some(item => item.quantity > item.stock)) {{ '{' }}
const outOfStock = items.filter(i => i.quantity > i.stock);
throw new ValidationError(`Insufficient stock for: ${{ '{' }}outOfStock.map(i => i.name).join(', '){{ '}' }}`);
{{ '}' }}
// Lines 120-135
if (coupon && coupon.expiresAt < new Date()) {{ '{' }}
throw new ValidationError('Coupon has expired');
{{ '}' }}
if (coupon && coupon.usageCount >= coupon.maxUsage) {{ '{' }}
throw new ValidationError('Coupon usage limit reached');
{{ '}' }}
```
Generate unit tests to cover these scenarios. Include:
1. Test for each branch
2. Boundary conditions
3. Descriptive test names
테스트 모범 사례
안티 패턴
- 순서에 따른 테스트
- 테스트 간에 공유되는 상태
- 모호한 이름: "작동해야 합니다"
- 관련되지 않은 여러 어설션
- 테스트가 너무 세부적임
- 과도한 모의(모의 테스트)
- 이유 없이 느린 테스트
- 불안정한 테스트 무시
모범 사례
- 독립적이고 격리된 테스트
- 각 테스트에 대한 새로운 설정
- 설명적인 이름
- 테스트를 위한 논리적 설명
- 구현이 아닌 테스트 동작
- 외부 종속성만 모의
- 공유 설정 최적화
- 불안정한 테스트 수정 또는 제거
테스트 품질 체크리스트
병합 전
- 모든 테스트가 로컬에서 통과됨
- 중요 코드의 적용 범위 >= 80%
- 불안정한 테스트 없음(3회 실행)
- 테스트 이름은 설명적입니다.
- 엣지 케이스가 적용됩니다.
- 오류 경로가 테스트되었습니다.
- 테스트에 console.log가 없습니다.
- 설비는 깨끗하고 재사용이 가능합니다.
- 모의는 현실적이다
- 테스트 속도가 빠릅니다(단위 <총 10초)
결론 및 다음 단계
테스트는 Claude Code가 정말 빛나는 곳입니다. 처음부터 완전한 테스트를 생성할 수 있습니다. 기존 코드에서 고려하지 않았을 수 있는 극단적인 경우를 제안하고, 개발 속도를 희생하지 않고도 높은 적용 범위를 유지할 수 있도록 도와줍니다.
기억하세요: Claude Code에서 생성된 테스트는 항상 검증됨. AI는 통과하는 테스트를 생성할 수 있지만 실제로 중요한 동작을 테스트하지는 않습니다. 또는 행동보다는 구현에 너무 묶여 있습니다.
에서 다음 기사 Claude Code를 사용하는 방법을 살펴보겠습니다. 전문 문서: 완전한 README, API 문서 OpenAPI, 아키텍처 결정 기록 및 JSDoc을 사용합니다.
기억해야 할 핵심 사항
- 피라미드: 70% 단위, 20% 통합, 10% E2E
- 단위: 완전한 격리, 모의 종속성
- 완성: 실제 DB로 API end-to-end 테스트
- TDD: 테스트를 먼저 작성하고 나중에 구현하세요.
- 적용 범위: 중요한 코드의 경우 80% 이상을 목표로 합니다.
- 비품: 재사용 가능한 데이터를 위한 팩토리 기능
- 확인하다: 생성된 테스트를 항상 확인하세요.







