테스트 기초 — Jest로 유닛 테스트 시작하기
테스트 코드를 작성하는 것은 주니어 개발자가 시니어로 성장하는 과정에서 반드시 익혀야 할 스킬입니다. Jest는 자바스크립트에서 가장 널리 쓰이는 테스트 프레임워크로, 별도 설정 없이 바로 사용할 수 있습니다.
설치와 첫 테스트
npm install --save-dev jest
// sum.js
function sum(a, b) {
return a + b;
}
module.exports = sum;
// sum.test.js
const sum = require("./sum");
test("1 + 2는 3이다", () => {
expect(sum(1, 2)).toBe(3);
});
주요 매처 (Matcher)
// 정확한 값 비교
expect(1 + 1).toBe(2); // ===
expect({ a: 1 }).toEqual({ a: 1 }); // 깊은 비교
// 참/거짓
expect(true).toBeTruthy();
expect(0).toBeFalsy();
expect(null).toBeNull();
expect(undefined).toBeUndefined();
expect("hello").toBeDefined();
// 숫자
expect(10).toBeGreaterThan(5);
expect(0.1 + 0.2).toBeCloseTo(0.3); // 부동소수점
// 문자열
expect("Hello World").toMatch(/World/);
expect("Hello").toContain("ell");
// 배열
expect([1, 2, 3]).toContain(2);
expect([{ a: 1 }, { b: 2 }]).toContainEqual({ a: 1 });
expect([1, 2, 3]).toHaveLength(3);
// 예외
expect(() => { throw new Error("에러!"); }).toThrow("에러!");
expect(() => { throw new TypeError(); }).toThrow(TypeError);
// 부정
expect(1).not.toBe(2);
expect([]).not.toContain(1);
describe와 테스트 구조
describe("Calculator", () => {
describe("add", () => {
test("양수 더하기", () => {
expect(add(1, 2)).toBe(3);
});
test("음수 더하기", () => {
expect(add(-1, -2)).toBe(-3);
});
test("0 더하기", () => {
expect(add(5, 0)).toBe(5);
});
});
describe("divide", () => {
test("정상 나누기", () => {
expect(divide(10, 2)).toBe(5);
});
test("0으로 나누면 에러", () => {
expect(() => divide(10, 0)).toThrow("0으로 나눌 수 없습니다");
});
});
});
setup과 teardown
describe("Database", () => {
let db;
beforeAll(() => {
// 전체 테스트 전 1회
db = connectDatabase();
});
afterAll(() => {
// 전체 테스트 후 1회
db.disconnect();
});
beforeEach(() => {
// 각 테스트 전
db.clear();
});
afterEach(() => {
// 각 테스트 후
});
test("데이터 삽입", () => {
db.insert({ id: 1 });
expect(db.count()).toBe(1);
});
});
모킹 (Mock)
// 함수 모킹
const mockFn = jest.fn();
mockFn("hello");
expect(mockFn).toHaveBeenCalledWith("hello");
expect(mockFn).toHaveBeenCalledTimes(1);
// 반환값 설정
const getId = jest.fn()
.mockReturnValueOnce(1)
.mockReturnValueOnce(2)
.mockReturnValue(99);
console.log(getId()); // 1
console.log(getId()); // 2
console.log(getId()); // 99
// 모듈 모킹
jest.mock("./api", () => ({
fetchUser: jest.fn().mockResolvedValue({ id: 1, name: "정훈" }),
}));
// 타이머 모킹
jest.useFakeTimers();
test("3초 후 콜백 실행", () => {
const callback = jest.fn();
setTimeout(callback, 3000);
jest.advanceTimersByTime(3000);
expect(callback).toHaveBeenCalled();
});
비동기 테스트
// async/await
test("사용자 조회", async () => {
const user = await fetchUser(1);
expect(user.name).toBe("정훈");
});
// Promise
test("데이터 로드", () => {
return fetchData().then((data) => {
expect(data).toBeDefined();
});
});
// resolves/rejects
test("성공 응답", () => {
return expect(fetchData()).resolves.toEqual({ id: 1 });
});
test("에러 응답", () => {
return expect(fetchBroken()).rejects.toThrow("에러");
});
스냅샷 테스트
test("UI 컴포넌트 렌더링", () => {
const tree = render(<Button label="클릭" />);
expect(tree).toMatchSnapshot();
// 첫 실행 시 스냅샷 생성, 이후 변경 감지
});
// 인라인 스냅샷
test("포맷팅", () => {
expect(formatDate(new Date("2026-01-01"))).toMatchInlineSnapshot(
`"2026년 1월 1일"`
);
});
테스트 작성 팁
// 1. AAA 패턴 (Arrange-Act-Assert)
test("할인 계산", () => {
// Arrange (준비)
const price = 10000;
const discountRate = 0.2;
// Act (실행)
const result = applyDiscount(price, discountRate);
// Assert (검증)
expect(result).toBe(8000);
});
// 2. 하나의 테스트에 하나의 검증
// 나쁜 예: 여러 동작을 한 테스트에서 검증
// 좋은 예: 각 동작을 별도 테스트로 분리
// 3. 테스트 이름은 명확하게
test("빈 배열에 아이템을 추가하면 길이가 1이 된다", () => {
const arr = [];
arr.push("item");
expect(arr).toHaveLength(1);
});
**기억하기 **:
toBe는===비교,toEqual은 깊은 비교입니다. 비동기 테스트는async/await를 사용하고, 외부 의존성은jest.mock으로 격리합니다. 테스트는 "Arrange-Act-Assert" 패턴으로 작성하면 읽기 쉽습니다.
댓글 로딩 중...