테마 전환

Vitest 단위 테스트 실전: TDD 흐름과 커버리지 설정

Easton editorial illustration: failed red test card, passing green test card, central refactor wrench, coverage gate

터미널에 찍힌 Test Suites: 1 failed, 47 passed 한 줄을 보고 있습니다. 코드 한 줄을 고치고 테스트가 끝날 때까지 28초를 기다립니다. 다시 한 줄을 고치면 또 28초입니다.

Jest에서 Vitest로 옮기기 전의 테스트 경험은 대략 이랬습니다.

당시 프로젝트에는 테스트 케이스가 거의 500개 있었습니다. npm test를 한 번 돌리면 Hacker News 두 페이지를 훑을 시간이 생겼습니다. 나중에 Vitest로 바꾸자 같은 테스트가 3초 조금 넘는 시간에 끝났습니다.

그래서 이번 글에서는 두 가지를 다룹니다. Vitest로 빠른 테스트 경험을 만드는 방법, 그리고 TDD(테스트 주도 개발) 방식으로 테스트 작성의 부담을 줄이는 방법입니다. 가격 포맷 함수 하나를 예제로 삼아 Red-Green-Refactor 순환을 끝까지 따라가고, 이어서 커버리지 설정, Mock 기법, 디버깅에 유용한 Vitest UI까지 정리하겠습니다.

왜 Vitest + TDD를 선택할까

먼저 숫자부터 보겠습니다.

5만 개 테스트
Vitest 3초 vs Jest 28-34초

SitePoint는 2026년에 비교 테스트를 진행했습니다. 테스트 케이스 5만 개를 기준으로 Vitest는 3초 만에 끝났고, Jest는 28-34초가 걸렸습니다. 조금 빠른 정도가 아니라 한 자릿수 차이가 납니다.

속도만 이유는 아닙니다. Jest로 ESM 모듈을 다뤄 본 적이 있다면 아마 그 함정을 밟아 봤을 겁니다. babel을 설치하고, transformers를 설정하고, jest.config.js 안의 여러 마법 문자열이 제대로 먹히기를 기대해야 합니다. Vitest는 다릅니다. ESM을 기본 지원하므로 별도 트랜스파일 설정이 필요 없습니다. 코드를 쓴 방식 그대로 테스트가 실행됩니다. 단순하고 명확합니다.

Vite 사용자에게 더 잘 맞는 부분도 있습니다. Vitest는 Vite 설정을 그대로 재사용합니다. vite.config.ts에 설정해 둔 alias, 환경 변수, 플러그인이 테스트 환경에 자동으로 이어집니다. Jest처럼 moduleNameMapper를 한 번 더 작성할 필요가 없습니다. 저는 처음 이 사실을 알았을 때 몇 초 동안 멍했습니다. 테스트 설정이 이렇게 가벼울 수도 있었던 겁니다.

도구 이야기를 했으니 이제 방법을 보겠습니다. TDD라는 말은 많이 들어 봤지만 꾸준히 실천하는 사람은 많지 않습니다. 핵심은 Red-Green-Refactor라는 순환입니다. 먼저 실패하는 테스트를 작성하고(Red), 그 테스트를 딱 통과시키는 코드를 작성한 뒤(Green), 마지막에 구조를 개선합니다(Refactor). 조금 반직관적으로 들립니다. 코드를 쓰기 전에 테스트부터 쓴다고요?

하지만 이 방식에는 장점이 있습니다. 작성하는 모든 코드는 테스트를 통과시키기 위해 존재합니다. 불필요한 로직도, “혹시 모르니” 넣는 코드도 줄어듭니다. 또 테스트를 먼저 쓰기 때문에 함수가 무엇을 해야 하는지, 무엇을 반환해야 하는지, 경계가 어디인지 먼저 생각하게 됩니다. 이 제약이 오히려 설계를 더 또렷하게 만듭니다.

Vitest의 watch 모드는 이 순환을 특히 매끄럽게 만듭니다. 파일을 저장하면 테스트가 바로 실행되고 결과가 터미널에 표시됩니다. 창을 바꿀 필요도, 명령을 직접 다시 입력할 필요도 없습니다. 옆에서 계속 확인해 주는 동료가 있는 느낌입니다. “여기 잘못 바꿨어요, 테스트가 깨졌습니다”, “이제 전부 녹색입니다” 같은 즉각적인 피드백이 이어집니다. 이 속도는 생각보다 쉽게 몰입 상태를 만듭니다.

TDD 실전: 함수 하나를 처음부터 개발하기

말로만 하면 감이 잘 오지 않습니다. TDD 방식으로 formatPrice() 함수를 만들어 보겠습니다. 숫자를 통화 표시로 포맷하는 함수입니다. 예를 들어 1234.5를 ¥1,234.50으로 바꿉니다.

Red 단계: 먼저 실패하는 테스트 작성

프로젝트를 열고 formatPrice.test.ts 파일을 새로 만듭니다.

// formatPrice.test.ts
import { describe, it, expect } from 'vitest'
import { formatPrice } from './formatPrice'

describe('formatPrice', () => {
  it('숫자를 위안화 통화 형식으로 포맷해야 한다', () => {
    expect(formatPrice(1234.5)).toBe('¥1,234.50')
  })
})

이제 npx vitest를 실행하면 터미널에 큼직한 빨간 에러가 나옵니다. Cannot find module './formatPrice'입니다. 아직 함수를 작성하지 않았기 때문입니다.

이게 맞습니다. 이것이 Red 단계입니다. 테스트가 실패했다는 것은 아직 구현되지 않은 요구사항을 정의했다는 뜻입니다. 많은 사람이 테스트를 먼저 쓰는 것을 이상하게 느낍니다. 하지만 반대로 생각해 보세요. 코드를 먼저 쓰고 테스트를 나중에 작성하면, 그 테스트가 정말 검증하려던 것을 검증하는지 어떻게 확신할 수 있을까요?

Green 단계: 테스트를 통과시키는 최소 코드 작성

이제 formatPrice.ts를 만들고 테스트가 통과할 만큼만 코드를 씁니다.

// formatPrice.ts
export function formatPrice(value: number): string {
  return '¥1,234.50'  // 먼저 반환값을 하드코딩합니다
}

다시 테스트를 실행합니다. 녹색입니다.

잠깐, 이렇게 하면 “속임수 아닌가요?”라고 말할 수 있습니다. 사실은 아닙니다. TDD는 테스트를 통과시키는 데 필요한 만큼만 코드를 쓰라고 말합니다. 하드코딩이든 가장 단순한 로직이든, 테스트가 통과하면 검증 가능한 기반이 생긴 것입니다. 그다음 새 테스트를 추가하고 코드를 고치며 한 단계씩 진행합니다.

테스트 케이스를 하나 더 추가해 보겠습니다.

it('서로 다른 숫자도 올바르게 처리해야 한다', () => {
  expect(formatPrice(0)).toBe('¥0.00')
  expect(formatPrice(99.99)).toBe('¥99.99')
})

테스트가 다시 빨간색이 됩니다. 이제는 하드코딩으로 버틸 수 없으니 실제 로직을 작성해야 합니다.

export function formatPrice(value: number): string {
  return `¥${value.toFixed(2).replace(/\B(?=(\d{3})+(?!\d))/g, ',')}`
}

테스트를 실행하면 모두 녹색입니다. 정규식은 조금 못생겼지만, 지금은 동작하면 됩니다.

Refactor 단계: 코드 구조 개선

테스트는 통과했지만 코드는 더 읽기 쉽게 만들 수 있습니다. 이때는 안심하고 리팩터링할 수 있습니다. 테스트가 지켜 주기 때문입니다. 잘못 바꾸면 바로 빨간색으로 알려 줍니다.

// 리팩터링한 버전
export function formatPrice(value: number): string {
  // Intl.NumberFormat을 사용하면 더 견고합니다
  return new Intl.NumberFormat('zh-CN', {
    style: 'currency',
    currency: 'CNY',
    minimumFractionDigits: 2,
  }).format(value)
}

테스트를 한 번 더 실행합니다. 여전히 전부 녹색입니다. 리팩터링이 끝났습니다.

이것이 Red-Green-Refactor 한 사이클입니다. 실패에서 시작하고, 가장 단순한 코드로 통과시킨 뒤, 구조를 개선합니다. 전체 과정에서 테스트가 받쳐 주기 때문에 망가뜨릴까 봐 겁낼 필요가 줄어듭니다. 각 단계가 작기 때문에 머리의 부담도 낮습니다. 처음부터 모든 경계 조건을 떠올릴 필요가 없습니다. 테스트가 다음 문제를 알려 줍니다.

실제 프로젝트에서는 보통 watch 모드로 이 순환을 돌립니다. 파일 저장 → 테스트 자동 실행 → 결과 확인 → 코드 수정 → 저장 → 다시 실행. 전체가 몇 초 안에 끝나고 에디터를 떠날 필요도 없습니다. “조금 바꾸면 바로 맞는지 알 수 있다”는 감각은 생각보다 든든합니다.

커버리지 설정과 CI 통합

테스트를 작성했다면 얼마나 검증했는지도 알아야 합니다. 커버리지 리포트는 바로 이 목적을 위해 씁니다.

기본 설정

vitest.config.ts에 커버리지 설정을 추가합니다.

// vitest.config.ts
import { defineConfig } from 'vitest/config'

export default defineConfig({
  test: {
    coverage: {
      provider: 'v8',      // 또는 'istanbul'. v8이 기본적으로 더 빠릅니다
      reporter: ['text', 'html', 'json-summary'],
      reportsDirectory: './coverage',
      include: ['src/**/*.ts'],
      exclude: ['src/**/*.test.ts', 'src/types/**'],
      thresholds: {
        statements: 80,
        branches: 75,
        functions: 80,
        lines: 80,
      },
    },
  },
})

provider는 v8과 istanbul 두 가지를 고를 수 있습니다. v8은 V8 엔진의 네이티브 커버리지 API를 사용하므로 더 빠릅니다. istanbul은 오래된 안정적인 선택지이고 호환성이 더 좋습니다. 프로젝트가 순수 Vite/Node 환경이라면 v8이면 충분합니다.

reporter는 출력 형식을 지정합니다. text는 터미널에 출력하고, html은 시각적 리포트를 만들며, json-summary는 CI 도구가 읽기 좋습니다.

임계값 설정

thresholds 부분은 조금 설명이 필요합니다. 네 가지 기준이 있습니다.

  • statements: 문장 커버리지입니다. 얼마나 많은 코드 문장이 실행됐는지 봅니다.
  • branches: 분기 커버리지입니다. if/else의 각 분기가 모두 테스트됐는지 봅니다.
  • functions: 함수 커버리지입니다. 얼마나 많은 함수가 호출됐는지 봅니다.
  • lines: 라인 커버리지입니다. statements와 비슷하지만 계산 방식이 조금 다릅니다.

저는 보통 thresholds를 75%-85% 사이에 둡니다. 너무 낮으면 의미가 없고, 너무 높으면 팀이 지칩니다. 경계 검사나 오류 처리처럼 100%까지 테스트하기 어려운 코드도 있기 때문입니다.

GitHub Actions 통합

커버리지의 가치가 가장 크게 드러나는 곳은 CI입니다. 기준에 못 미치는 PR을 자동으로 막을 수 있습니다. .github/workflows/test.yml에 다음 단계를 추가합니다.

- name: Run tests with coverage
  run: npm run test -- --coverage

- name: Check coverage threshold
  run: |
    COVERAGE=$(cat coverage/coverage-summary.json | jq '.total.lines.pct')
    if (( $(echo "$COVERAGE < 80" | bc -l) )); then
      echo "Coverage $COVERAGE% is below threshold 80%"
      exit 1
    fi

이렇게 하면 커버리지가 80%보다 낮을 때 PR을 머지할 수 없습니다. 팀원은 제출 전에 테스트가 충분한지 확인해야 합니다.

리포트 읽기

npx vitest --coverage를 실행하면 터미널에 다음과 비슷한 결과가 나옵니다.

 % Stmts   % Branch   % Funcs   % Lines   Uncovered Line
----------|----------|----------|----------|----------------
  82.45    |   76.32   |   85.71   |   82.45   | 23-25, 67

Uncovered Line은 테스트되지 않은 코드 줄을 보여 줍니다. coverage/index.html을 열면 더 자세한 시각적 리포트를 볼 수 있습니다. 초록색은 테스트된 코드이고, 빨간색은 테스트되지 않은 코드입니다.

솔직히 처음 커버리지를 챙길 때는 저도 강박이 조금 생겼습니다. 모든 줄을 다 테스트하고 싶었습니다. 나중에는 그럴 필요가 없다는 걸 알게 됐습니다. 80% 커버리지면 보통 핵심 로직과 주요 분기를 이미 덮습니다. 나머지 20%는 극단적인 경계 상황인 경우가 많고, 억지로 테스트하면 오히려 시간이 낭비됩니다.

Mock 삼총사: vi.fn, vi.spy, vi.mock

테스트에서 가장 골치 아픈 부분은 대개 외부 의존성입니다. API 요청, 타이머, 서드파티 라이브러리 같은 것들입니다. Vitest는 세 가지 Mock 방식을 제공하며 각각 쓰임새가 다릅니다.

vi.fn(): 가짜 함수 만들기

원래 함수가 무엇이었는지는 중요하지 않고, 어떤 식으로 호출됐는지만 확인하고 싶다면 vi.fn()을 씁니다.

test('콜백 함수는 한 번 호출되어야 한다', () => {
  const callback = vi.fn()

  callMeMaybe(callback)

  expect(callback).toHaveBeenCalledTimes(1)
  expect(callback).toHaveBeenCalledWith('hello')
})

여기서 callback은 완전히 새로운 함수입니다. 자신이 호출된 횟수, 인자, 반환값을 기록합니다. mockReturnValue로 반환값을 지정할 수 있고, mockImplementation으로 동작을 지정할 수도 있습니다.

vi.spy(): 실제 함수 감시하기

때로는 함수를 대체하고 싶지 않고, 호출됐는지와 어떤 인자가 전달됐는지만 보고 싶습니다. 이때는 vi.spyOn을 씁니다.

test('console.log를 호출해야 한다', () => {
  const logSpy = vi.spyOn(console, 'log')

  greet('World')

  expect(logSpy).toHaveBeenCalledWith('Hello, World!')
  logSpy.mockRestore()  // 복구를 잊지 마세요
})

spy는 원래 함수의 동작을 유지하면서 호출을 감시합니다. 사용한 뒤에는 mockRestore()를 호출해야 합니다. 그렇지 않으면 다른 테스트에 영향을 줄 수 있습니다.

vi.mock(): 전체 모듈 대체하기

API 응답을 흉내 내거나 서드파티 라이브러리를 바꿔야 한다면 vi.mock을 씁니다. 이 방식은 전체 모듈을 대체합니다.

// axios 모킹
vi.mock('axios', () => ({
  default: {
    get: vi.fn(() => Promise.resolve({ data: { name: 'test' } }))
  }
}))

test('getUser는 사용자 데이터를 반환해야 한다', async () => {
  const user = await getUser(1)

  expect(user.name).toBe('test')
  expect(axios.get).toHaveBeenCalledWith('/users/1')
})

vi.mock에는 한 가지 주의할 점이 있습니다. 함수 안에 쓰든 if 문 안에 쓰든 파일 맨 위로 hoist됩니다. 그래서 mock 내용은 다른 변수에 의존하면 안 됩니다.

무엇을 선택해야 할까?

간단히 정리하면 이렇습니다.

  • 가짜 함수만 필요하다면 vi.fn()
  • 실제 함수를 감시하고 싶다면 vi.spy()
  • 전체 모듈을 대체해야 한다면 vi.mock()

저도 예전에는 이 셋을 자주 헷갈렸습니다. 나중에 기억법을 하나 만들었습니다. fn은 가짜를 만들고, spy는 지켜보고, mock은 통째로 바꿉니다. 생각보다 잘 외워집니다.

정리는 중요합니다

테스트가 서로 영향을 주지 않는 것은 신뢰할 수 있는 테스트의 기본입니다. 각 테스트가 끝난 뒤에는 mock을 정리하세요.

afterEach(() => {
  vi.restoreAllMocks()
})

또는 vitest 설정에서 전역으로 켤 수 있습니다.

test: {
  restoreMocks: true
}

Vitest UI와 디버깅 팁

명령줄만으로도 테스트 결과를 볼 수는 있습니다. 하지만 더 직관적인 경험을 원한다면 Vitest UI를 써 볼 만합니다.

시각적 인터페이스 시작하기

npx vitest --ui

브라우저가 자동으로 열리고 인터페이스가 표시됩니다. 왼쪽에는 테스트 목록, 오른쪽에는 상세 정보가 있습니다. 아무 테스트나 클릭하면 전체 출력, 오류 스택, 실행 시간을 볼 수 있습니다. 커버리지 버튼도 있어서 누르면 앞에서 말한 HTML 리포트가 열립니다.

이 도구는 디버깅에 특히 잘 맞습니다. 테스트가 깨졌을 때 터미널에서 로그를 뒤질 필요 없이 UI에서 오류 정보를 바로 확인할 수 있습니다. 옆에는 코드가 있고, 수정 후 저장하면 인터페이스가 자동으로 새로고침됩니다.

watch 모드: 영향을 받은 테스트만 실행

평소 개발할 때 저는 npx vitest로 watch 모드를 실행합니다. 증분 테스트가 꽤 똑똑합니다. utils/formatPrice.ts를 수정하면 이 파일과 관련된 테스트만 실행하고 전체를 다시 돌리지 않습니다.

테스트가 많아질수록 이 차이는 시간을 크게 줄여 줍니다. 제 프로젝트 중 하나는 테스트가 800개가 넘었고, 전체 실행은 4초였지만 증분 실행은 보통 수백 밀리초면 끝났습니다.

디버깅 팁

테스트가 깨졌다면 몇 가지 자주 쓰는 방법이 있습니다.

단일 테스트만 실행: it 뒤에 .only를 붙입니다.

it.only('이 테스트에 문제가 있으니 단독으로 실행한다', () => {
  // ...
})

테스트 건너뛰기: .skip을 붙입니다.

it.skip('이 테스트는 일단 건너뛴다', () => {
  // ...
})

스냅샷 업데이트: 컴포넌트 구조를 바꿔서 스냅샷 테스트가 깨졌을 때 사용합니다.

npx vitest -u  # -u는 --update의 줄임말입니다

console.log 디버깅: 맞습니다. 오래된 방법이 여전히 가장 잘 먹힐 때가 많습니다. Vitest는 console 출력을 테스트 결과에 그대로 보여 줍니다.

자주 만나는 오류

오류원인해결
Cannot find module경로 alias 설정이 잘못됨vitest.config의 alias 확인
vi.mock is not a functionimport 방식 오류import { vi } from 'vitest' 사용
테스트 시간대가 맞지 않음기본값이 UTCsetup에서 process.env.TZ = 'Asia/Shanghai' 설정

이 함정들은 저도 다 밟아 봤습니다. 특히 시간대 문제는 CI에서 로컬 시간 기준 테스트가 전부 깨졌고, 반나절 가까이 파고 나서야 원인이 시간대라는 걸 찾았습니다.

결론

길게 이야기했지만 핵심은 하나입니다. Vitest + TDD는 테스트 작성의 고통을 확실히 줄여 줍니다.

속도 면에서 Jest의 수십 초가 몇 초로 줄어드는 변화는 단순한 숫자 차이가 아닙니다. 경험의 차이입니다. 코드를 고치고 테스트를 기다리는 사이를 계속 오가지 않아도 되고, “한 줄 고쳤는데 한참 기다리는” 답답함을 견디지 않아도 됩니다. ESM 기본 지원과 Vite 설정 재사용도 실제로 시간을 아껴 줍니다.

TDD의 Red-Green-Refactor 순환은 처음에는 조금 반직관적입니다. 하지만 몇 번 해 보면 장점이 보입니다. 각 단계가 작고, 각 단계마다 검증이 있으며, 머리의 부담이 낮습니다. 처음부터 완벽한 설계를 만들 필요가 없습니다. 테스트가 문제를 발견하게 해 주고, 우리는 반복하며 개선하면 됩니다.

커버리지 설정과 Mock 기법은 도구 차원의 문제입니다. 익혀 두면 더 견고한 테스트를 작성하는 데 도움이 됩니다. 하지만 더 중요한 것은 테스트를 쓰는 습관입니다. 숫자를 쫓기 위해서가 아니라, 코드에 더 큰 확신을 갖기 위해서입니다.

이미 프로젝트에서 Vite를 쓰고 있다면 Jest에서 Vitest로 옮기는 비용은 꽤 낮습니다. npm add -D vitest 한 줄을 추가하고 Jest 테스트 문법을 Vitest에 맞게 조금만 바꾸면 됩니다. 거의 비슷합니다. 아직 망설이고 있다면 작은 모듈 하나에서 먼저 시도해 보세요. watch 모드의 즉각적인 피드백을 직접 느껴 보는 것이 가장 빠릅니다.

지금 Vitest로 첫 테스트를 실행해 보고 TDD 순환을 한 번 경험해 보세요. “바꾸자마자 맞는지 알 수 있다”는 그 안정감이 생각보다 오래갑니다. 어쩌면 저처럼 테스트 작성이 조금은 좋아질지도 모릅니다.

Vitest TDD 실전 흐름

TDD 방식으로 함수를 처음부터 개발하고 커버리지 리포트를 설정합니다.

⏱️ Estimated time: 30 min

  1. 1

    Step 1: Vitest 설치

    Vite 프로젝트에 Vitest를 추가합니다:

    npm add -D vitest

    추가 설정 없이 Vitest가 Vite 설정을 자동으로 재사용합니다.
  2. 2

    Step 2: Red 단계: 실패하는 테스트 작성

    테스트 파일을 만들고 반드시 실패하는 테스트를 작성합니다:

    import { describe, it, expect } from 'vitest'
    import { formatPrice } from './formatPrice'

    describe('formatPrice', () => {
    it('통화 형식으로 포맷해야 한다', () => {
    expect(formatPrice(1234.5)).toBe('¥1,234.50')
    })
    })

    npx vitest를 실행해 테스트가 실패하는지 확인합니다(빨간색).
  3. 3

    Step 3: Green 단계: 최소 코드 작성

    구현 파일을 만들고 테스트가 딱 통과할 만큼만 코드를 작성합니다:

    export function formatPrice(value: number): string {
    return '¥1,234.50' // 먼저 하드코딩합니다
    }

    테스트를 실행해 통과하는지 확인합니다(녹색).
  4. 4

    Step 4: Refactor 단계: 코드 개선

    Intl.NumberFormat으로 리팩터링합니다:

    export function formatPrice(value: number): string {
    return new Intl.NumberFormat('zh-CN', {
    style: 'currency',
    currency: 'CNY',
    }).format(value)
    }

    테스트가 여전히 통과하는지 확인합니다.
  5. 5

    Step 5: 커버리지 설정

    vitest.config.ts에 다음 설정을 추가합니다:

    test: {
    coverage: {
    provider: 'v8',
    thresholds: { statements: 80, branches: 75 }
    }
    }

    npx vitest --coverage를 실행해 리포트를 확인합니다.

FAQ

Vitest와 Jest의 주요 차이는 무엇인가요?
Vitest는 Vite에 맞춰 설계되어 ESM을 기본 지원하며 Jest보다 5-10배 빠릅니다. Vitest는 Vite 설정(alias, 환경 변수)을 자동으로 재사용하므로 Jest처럼 moduleNameMapper를 따로 설정할 필요가 없습니다.
TDD의 Red-Green-Refactor 순환은 어떻게 하나요?
세 단계로 반복합니다:

• Red: 먼저 실패하는 테스트를 작성해 요구사항을 정의합니다.
• Green: 테스트를 통과시키는 최소 코드를 작성합니다. 하드코딩도 가능합니다.
• Refactor: 테스트의 보호 아래 코드 구조를 개선합니다.

각 단계가 작기 때문에 부담이 낮고, 테스트가 전체 과정을 받쳐 줍니다.
커버리지 임계값은 어느 정도가 적절한가요?
75%-85%를 권장합니다. 너무 낮으면 의미가 없고, 너무 높으면 팀이 커버리지 숫자에 쫓기게 됩니다. 80%면 보통 핵심 로직은 이미 대부분 커버되며, 나머지 20%는 극단적인 경계 사례인 경우가 많아 억지로 테스트하면 오히려 시간이 낭비됩니다.
vi.fn, vi.spy, vi.mock은 어떻게 선택하나요?
상황에 따라 고릅니다:

• vi.fn(): 새 가짜 함수를 만들고 호출 횟수와 인자를 기록합니다.
• vi.spy(): 기존 함수를 감시하면서 원래 동작은 유지합니다. 사용 후 mockRestore()가 필요합니다.
• vi.mock(): 전체 모듈을 대체하며 API나 서드파티 라이브러리를 흉내 낼 때 씁니다.

기억법은 간단합니다. fn은 가짜를 만들고, spy는 지켜보고, mock은 통째로 바꿉니다.
Vitest watch 모드의 장점은 무엇인가요?
증분 테스트는 영향을 받은 파일만 실행합니다. 800개 테스트 전체 실행이 4초라면 증분 실행은 보통 수백 밀리초면 충분합니다. 파일을 저장하면 바로 테스트가 돌기 때문에 창을 바꾸지 않고도 흐름을 유지할 수 있습니다.
테스트의 시간대 문제는 어떻게 해결하나요?
Vitest는 기본적으로 UTC 시간대를 사용합니다. vitest.config.ts의 setupFiles에서 process.env.TZ = 'Asia/Shanghai'를 설정하거나 테스트 파일 맨 앞에서 직접 설정하면 됩니다.

3분 읽기 · 게시일: 2026년 4월 29일 · 수정일: 2026년 10월 21일

댓글

GitHub로 로그인하여 댓글을 남기세요

Easton BlogEaston Blog