TDD 완벽 마스터
TDD의 핵심 개념과 실전 활용법
학습 항목
본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.
이미지 로딩 중...
Jest 디자인 패턴 테스트 전략
효율적인 테스트 코드를 작성하기 위한 Jest 디자인 패턴과 베스트 프랙티스를 학습합니다. AAA 패턴, 테스트 더블, 테스트 픽스처 등 실무에서 자주 사용되는 패턴들을 다룹니다.
들어가며
이 글에서는 Jest 디자인 패턴 테스트 전략에 대해 상세히 알아보겠습니다. 총 12가지 주요 개념을 다루며, 각각의 개념에 대한 설명과 실제 코드 예제를 함께 제공합니다.
목차
- AAA_패턴
- 테스트_픽스처_패턴
- Mock_함수_패턴
- Spy_패턴
- 팩토리_함수_패턴
- 파라미터화_테스트_패턴
- Setup_Teardown_패턴
- 모듈_Mock_패턴
- Snapshot_테스팅_패턴
- Custom_Matcher_패턴
- Test_Double_패턴
- 비동기_패턴
1. AAA 패턴
개요
Arrange-Act-Assert 패턴은 테스트 코드를 세 단계로 명확히 구분하여 가독성을 높이는 기본 디자인 패턴입니다.
코드 예제
test('사용자 이름을 올바르게 포맷팅한다', () => {
// Arrange: 테스트 준비
const user = { firstName: 'John', lastName: 'Doe' };
// Act: 실제 동작 실행
const fullName = formatUserName(user);
// Assert: 결과 검증
expect(fullName).toBe('John Doe');
});
설명
테스트를 준비-실행-검증 세 단계로 나누어 코드의 의도를 명확히 전달하고, 유지보수를 쉽게 만듭니다.
2. 테스트 픽스처 패턴
개요
반복적으로 사용되는 테스트 데이터를 beforeEach로 설정하여 코드 중복을 제거하는 패턴입니다.
코드 예제
describe('UserService', () => {
let testUser;
beforeEach(() => {
testUser = { id: 1, name: 'Test User', email: 'test@example.com' };
});
test('사용자 정보를 반환한다', () => {
expect(getUserInfo(testUser.id)).toEqual(testUser);
});
});
설명
각 테스트 실행 전에 공통 데이터를 초기화하여 테스트 간 독립성을 보장하고 코드 재사용성을 높입니다.
3. Mock 함수 패턴
개요
외부 의존성을 jest.fn()으로 대체하여 격리된 단위 테스트를 작성하는 패턴입니다.
코드 예제
test('API 호출 시 콜백이 실행된다', () => {
const mockCallback = jest.fn();
const fetchData = (callback) => callback('data');
fetchData(mockCallback);
expect(mockCallback).toHaveBeenCalledWith('data');
expect(mockCallback).toHaveBeenCalledTimes(1);
});
설명
Mock 함수를 사용하면 함수 호출 여부, 호출 횟수, 전달된 인자 등을 정확히 검증할 수 있습니다.
4. Spy 패턴
개요
실제 함수의 동작은 유지하면서 호출 정보만 추적하는 jest.spyOn() 패턴입니다.
코드 예제
test('로그 함수가 올바르게 호출된다', () => {
const consoleSpy = jest.spyOn(console, 'log');
logMessage('Hello World');
expect(consoleSpy).toHaveBeenCalledWith('Hello World');
consoleSpy.mockRestore();
});
설명
Spy는 원본 함수를 유지하면서 호출을 감시하며, mockRestore()로 원래 상태로 복원할 수 있습니다.
5. 팩토리 함수 패턴
개요
테스트 데이터 생성을 위한 팩토리 함수를 만들어 유연하고 재사용 가능한 테스트를 작성하는 패턴입니다.
코드 예제
const createUser = (overrides = {}) => ({
id: 1,
name: 'John Doe',
email: 'john@example.com',
...overrides
});
test('특정 이메일의 사용자를 생성한다', () => {
const user = createUser({ email: 'custom@example.com' });
expect(user.email).toBe('custom@example.com');
});
설명
기본값을 제공하면서 필요한 속성만 오버라이드할 수 있어 테스트 데이터 생성이 간편해집니다.
6. 파라미터화 테스트 패턴
개요
test.each()를 사용하여 동일한 테스트 로직을 여러 입력값으로 반복 실행하는 패턴입니다.
코드 예제
test.each([
[1, 1, 2],
[2, 3, 5],
[5, 10, 15]
])('add(%i, %i)는 %i를 반환한다', (a, b, expected) => {
expect(add(a, b)).toBe(expected);
});
설명
여러 케이스를 간결하게 테스트할 수 있어 엣지 케이스 검증에 효과적이고 코드 중복을 줄입니다.
7. Setup Teardown 패턴
개요
beforeAll과 afterAll을 사용하여 테스트 전후의 환경을 관리하는 패턴입니다.
코드 예제
describe('Database tests', () => {
beforeAll(() => database.connect());
afterAll(() => database.disconnect());
test('데이터를 저장한다', async () => {
await database.save({ name: 'Test' });
expect(database.count()).toBe(1);
});
});
설명
테스트 스위트 전체에서 한 번만 실행되는 설정과 정리 작업을 정의하여 테스트 성능을 최적화합니다.
8. 모듈 Mock 패턴
개요
jest.mock()을 사용하여 전체 모듈을 모의 객체로 대체하는 패턴입니다.
코드 예제
jest.mock('./api');
const { fetchUser } = require('./api');
test('API에서 사용자를 가져온다', async () => {
fetchUser.mockResolvedValue({ id: 1, name: 'John' });
const user = await getUser(1);
expect(user.name).toBe('John');
});
설명
외부 API나 데이터베이스 같은 의존성을 완전히 격리하여 빠르고 안정적인 테스트를 작성할 수 있습니다.
9. Snapshot 테스팅 패턴
개요
컴포넌트나 객체의 출력을 스냅샷으로 저장하고 변경사항을 추적하는 패턴입니다.
코드 예제
test('사용자 프로필을 올바르게 렌더링한다', () => {
const profile = {
name: 'John Doe',
age: 30,
email: 'john@example.com'
};
expect(profile).toMatchSnapshot();
});
설명
복잡한 데이터 구조나 UI 출력의 예상치 못한 변경을 자동으로 감지하여 회귀 버그를 방지합니다.
10. Custom Matcher 패턴
개요
expect.extend()로 도메인 특화 매처를 만들어 테스트 가독성을 높이는 패턴입니다.
코드 예제
expect.extend({
toBeValidEmail(received) {
const pass = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(received);
return {
pass,
message: () => `${received}는 유효한 이메일이 아닙니다`
};
}
});
test('이메일 형식을 검증한다', () => {
expect('test@example.com').toBeValidEmail();
});
설명
프로젝트에 특화된 검증 로직을 재사용 가능한 매처로 만들어 테스트 코드의 표현력을 향상시킵니다.
11. Test Double 패턴
개요
Stub, Fake 등 다양한 테스트 더블을 활용하여 의존성을 제어하는 패턴입니다.
코드 예제
const fakeDatabase = {
users: [],
save(user) { this.users.push(user); },
find(id) { return this.users.find(u => u.id === id); }
};
test('사용자를 저장하고 조회한다', () => {
fakeDatabase.save({ id: 1, name: 'John' });
expect(fakeDatabase.find(1).name).toBe('John');
});
설명
실제 구현 대신 간단한 가짜 객체를 사용하여 테스트 속도를 높이고 외부 의존성 없이 테스트할 수 있습니다.
12. 비동기 패턴
개요
async/await와 resolves/rejects를 활용하여 비동기 코드를 테스트하는 패턴입니다.
코드 예제
test('비동기 데이터 페칭을 검증한다', async () => {
const promise = fetchUserData(1);
await expect(promise).resolves.toHaveProperty('name');
await expect(promise).resolves.toMatchObject({ id: 1 });
});
설명
프로미스 기반 코드를 명확하게 테스트하며, 성공과 실패 케이스를 모두 검증할 수 있습니다.
마치며
이번 글에서는 Jest 디자인 패턴 테스트 전략에 대해 알아보았습니다. 총 12가지 개념을 다루었으며, 각각의 사용법과 예제를 살펴보았습니다.
관련 태그
#Jest #TestingPatterns #AAA #Mocking #TDD