테스트
Testing
코드가 예상대로 동작하는지 검증. 유닛, 통합, E2E 테스트로 구분. TDD는 테스트 우선 개발.
Testing
코드가 예상대로 동작하는지 검증. 유닛, 통합, E2E 테스트로 구분. TDD는 테스트 우선 개발.
테스트(Testing)는 소프트웨어가 예상대로 동작하는지 검증하는 활동입니다. 버그를 조기에 발견하고, 리팩토링 시 안전망을 제공하며, 코드의 동작을 문서화합니다. 품질 보증(QA)의 핵심입니다.
테스트 피라미드에서 유닛 테스트(단위), 통합 테스트, E2E 테스트(종단간)로 계층화됩니다. 유닛 테스트가 가장 많고 빠르며, E2E로 갈수록 적고 느립니다. 70/20/10 비율을 권장합니다.
TDD(Test-Driven Development)는 테스트를 먼저 작성하고 코드를 구현합니다. Red(실패) -> Green(통과) -> Refactor(개선) 사이클로 진행합니다. BDD(Behavior-Driven Development)는 사용자 행동 관점에서 Given-When-Then으로 테스트를 기술합니다.
실무에서는 CI에서 모든 테스트를 자동 실행합니다. 커버리지 80% 이상을 목표로 하되, 숫자보다 중요 로직의 테스트 여부가 중요합니다. 테스트 속도를 위해 모킹을 활용하고, 플레이키(flaky) 테스트는 즉시 수정합니다.
// Jest 유닛 테스트 예제
describe('calculatePrice', () => {
// 기본 케이스
it('should calculate price with no discount', () => {
const result = calculatePrice(100, 0);
expect(result).toBe(100);
});
// 할인 적용
it('should apply percentage discount correctly', () => {
const result = calculatePrice(100, 20);
expect(result).toBe(80);
});
// 엣지 케이스
it('should handle 100% discount', () => {
const result = calculatePrice(100, 100);
expect(result).toBe(0);
});
// 에러 케이스
it('should throw error for negative price', () => {
expect(() => calculatePrice(-100, 10)).toThrow('Invalid price');
});
});
// 비동기 테스트
describe('UserService', () => {
it('should fetch user by id', async () => {
const mockUser = { id: 1, name: 'John' };
jest.spyOn(api, 'getUser').mockResolvedValue(mockUser);
const result = await userService.getUserById(1);
expect(result).toEqual(mockUser);
expect(api.getUser).toHaveBeenCalledWith(1);
});
});
// Integration Test (Supertest)
describe('POST /api/orders', () => {
it('should create order and return 201', async () => {
const orderData = { productId: 1, quantity: 2 };
const response = await request(app)
.post('/api/orders')
.send(orderData)
.set('Authorization', `Bearer ${testToken}`);
expect(response.status).toBe(201);
expect(response.body.orderId).toBeDefined();
});
});
// package.json scripts
// "scripts": {
// "test": "jest",
// "test:watch": "jest --watch",
// "test:coverage": "jest --coverage",
// "test:ci": "jest --ci --coverage --reporters=default --reporters=jest-junit"
// }
시니어: "결제 로직 변경했는데, 테스트 커버리지 어떤가요?"
주니어: "해당 모듈 95%이고, 경계값 케이스랑 에러 핸들링 테스트 다 추가했습니다."
면접관: "테스트 피라미드에서 각 계층의 특징을 설명해주세요."
지원자: "유닛 테스트는 빠르고 격리된 함수/클래스 단위를 테스트합니다. 통합 테스트는 모듈 간 상호작용을, E2E 테스트는 실제 사용자 시나리오를 검증합니다. 하위 계층이 많고 빠를수록 디버깅이 쉽습니다."
리뷰어: "이 테스트는 외부 API를 실제로 호출하는데, CI에서 불안정하지 않을까요?"
개발자: "mockResolvedValue로 모킹 처리하겠습니다. 실제 API 테스트는 별도 integration 스위트로 분리할게요."