2단계
vitest 기본 + mock 패턴
30 분
vitest 기본 + mock 패턴
Jest 의 후계로 자리잡은 vitest. Vite 와 네이티브 호환 + ESM 우선 + 빠름.
1. 설치
pnpm add -D vitest @vitest/ui
package.json 스크립트:
{ "scripts": { "test": "vitest run", "test:watch": "vitest" } }
2. 첫 테스트
// src/lib/format.test.ts
import { describe, it, expect } from "vitest";
import { formatDate } from "./format";
describe("formatDate", () => {
it("YYYY-MM-DD 형식", () => {
expect(formatDate(new Date("2026-05-06"))).toBe("2026-05-06");
});
});
3. 환경 — node vs jsdom
// vitest.config.ts
export default defineConfig({
test: {
environment: "node", // DOM 미사용 기본
globals: true, // describe/it/expect 전역
},
});
DOM · window 를 쓰는 코드는 environment: "jsdom". 파일 단위 오버라이드:
// @vitest-environment jsdom
4. vi.hoisted — mock 순서 문제 해결
import { vi, describe, it, expect } from "vitest";
const { mockQuery } = vi.hoisted(() => ({ mockQuery: vi.fn() }));
vi.mock("@/shared/lib/db", () => ({ pool: { query: mockQuery } }));
// 이제 import 한 코드가 이 mock 을 사용
import { getUserById } from "./user-repo";
describe("getUserById", () => {
it("쿼리 결과 반환", async () => {
mockQuery.mockResolvedValueOnce({ rows: [{ id: 1 }] });
expect(await getUserById(1)).toEqual({ id: 1 });
});
});
vi.mock 은 호이스팅되지만 변수 참조가 불가능. vi.hoisted 로 mock 생성도 함께 호이스팅.
5. 환경변수 · 전역 stub
import { beforeEach, afterEach } from "vitest";
beforeEach(() => {
vi.stubEnv("REVALIDATE_URL", "http://localhost:3000");
vi.resetModules();
});
afterEach(() => {
vi.unstubAllEnvs();
vi.unstubAllGlobals();
});
it("fetch 호출", async () => {
const fetchMock = vi.fn().mockResolvedValue({ ok: true, status: 200 });
vi.stubGlobal("fetch", fetchMock);
await triggerRevalidate();
expect(fetchMock).toHaveBeenCalled();
});
resetModules + stubEnv 조합으로 환경변수 분기 테스트.
6. React 컴포넌트 — testing-library
pnpm add -D @testing-library/react @testing-library/jest-dom
// @vitest-environment jsdom
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
it("클릭 시 증가", async () => {
render(<Counter />);
await userEvent.click(screen.getByRole("button", { name: /increment/i }));
expect(screen.getByText("1")).toBeInTheDocument();
});
7. snapshot — 신중히
expect(user).toMatchSnapshot();
편하지만 남용하면 "스냅샷 덩어리" 가 됨. 복잡한 출력만 선별적으로.
8. coverage
pnpm add -D @vitest/coverage-v8
vitest run --coverage
vitest.config.ts:
test: {
coverage: {
provider: "v8",
exclude: ["**/*.test.ts", "**/dist/**"],
thresholds: { lines: 70, functions: 70, branches: 70 },
},
}
9. 자주 걸리는 자리
- vi.mock 변수 참조 에러 — vi.hoisted 사용
- afterEach 정리 누락 — env stub 남아 다른 테스트 오염
- jsdom 에서 window 없음 —
environment: "jsdom"지정 - snapshot 오래되면 의미 없음 —
vitest -u로 주기적 갱신 + 리뷰
하고픈 말
vi.hoisted + stubEnv + stubGlobal 셋만 확실히 잡으면 사실상 모든 모킹 상황에 대응 가능합니다.
Next
- 03-pytest-fixtures