테스트 코드를 작성하는 것은 주니어 개발자가 시니어로 성장하는 과정에서 반드시 익혀야 할 스킬입니다. Jest는 자바스크립트에서 가장 널리 쓰이는 테스트 프레임워크로, 별도 설정 없이 바로 사용할 수 있습니다.

설치와 첫 테스트

BASH
npm install --save-dev jest
JS
// 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)

JS
// 정확한 값 비교
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와 테스트 구조

JS
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

JS
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)

JS
// 함수 모킹
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();
});

비동기 테스트

JS
// 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("에러");
});

스냅샷 테스트

JS
test("UI 컴포넌트 렌더링", () => {
  const tree = render(<Button label="클릭" />);
  expect(tree).toMatchSnapshot();
  // 첫 실행 시 스냅샷 생성, 이후 변경 감지
});

// 인라인 스냅샷
test("포맷팅", () => {
  expect(formatDate(new Date("2026-01-01"))).toMatchInlineSnapshot(
    `"2026년 1월 1일"`
  );
});

테스트 작성 팁

JS
// 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" 패턴으로 작성하면 읽기 쉽습니다.

댓글 로딩 중...