Skip to content
Vitest 3
Main Navigation 가이드 & API구성브라우저 모드고급 API
3.2.0
2.1.9
1.6.1
0.34.6

한국어

English
简体中文
繁體中文
Español
Français
Русский
Português – Brasil
Deutsch
日本語
Italiano
Polski
Türkçe
čeština
magyar

한국어

English
简体中文
繁體中文
Español
Français
Русский
Português – Brasil
Deutsch
日本語
Italiano
Polski
Türkçe
čeština
magyar

외관

Sidebar Navigation

소개

Vitest를 선택하는 이유

시작하기

기능

Vitest 구성하기

API

테스트 API 참조

Mock 함수

Vi

expect

expectTypeOf

assert

assertType

가이드

명령줄 인터페이스

테스트 필터링

테스트 프로젝트

리포터

커버리지

스냅샷

모킹

병렬 처리

타입 검사

Vitest UI

소스 내 테스팅

테스트 컨텍스트

테스트 어노테이션

테스트 환경

매처 확장하기

IDE 통합

디버깅

일반적인 오류

마이그레이션 가이드

Vitest 3.0으로 마이그레이션

Jest에서 마이그레이션

성능

테스트 성능 프로파일링

성능 향상

브라우저 모드

고급 API

다른 테스트 러너와의 비교

이 페이지에서

모킹 ​

테스트를 작성할 때 내부 또는 외부 서비스의 "가짜" 버전을 생성해야 하는 경우가 필연적으로 발생합니다. 이를 일반적으로 **모킹(mocking)**이라고 부릅니다. Vitest는 vi 헬퍼를 통해 유틸리티 함수를 제공합니다. 이 함수는 vitest에서 가져오거나 global 설정이 활성화된 경우 전역으로 액세스할 수 있습니다.

WARNING

각 테스트 실행 전후에 항상 목(mock)을 지우거나 복원하여 모킹 상태 변경을 되돌리는 것을 잊지 마세요! 자세한 내용은 mockReset 문서를 참조하세요.

만약 vi.fn, vi.mock 또는 vi.spyOn 메서드에 익숙하지 않다면, 먼저 API 섹션을 확인해 보세요.

날짜 ​

테스트의 일관성을 보장하기 위해 때때로 날짜를 제어해야 할 필요가 있습니다. Vitest는 타이머 및 시스템 날짜 조작을 위해 @sinonjs/fake-timers 패키지를 사용합니다. 특정 API에 대한 자세한 내용은 여기에서 확인할 수 있습니다.

예시 ​

js
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';

const businessHours = [9, 17];

function purchase() {
  const currentHour = new Date().getHours();
  const [open, close] = businessHours;

  if (currentHour > open && currentHour < close) {
    return { message: 'Success' };
  }

  return { message: 'Error' };
}

describe('purchasing flow', () => {
  beforeEach(() => {
    // Vitest에 모의 시간을 사용한다고 알립니다.
    vi.useFakeTimers();
  });

  afterEach(() => {
    // 각 테스트 실행 후 날짜를 복원합니다.
    vi.useRealTimers();
  });

  it('allows purchases within business hours', () => {
    // 업무 시간 내로 시간을 설정합니다.
    const date = new Date(2000, 1, 1, 13);
    vi.setSystemTime(date);

    // Date.now()를 호출하면 위에 설정된 날짜가 반환됩니다.
    expect(purchase()).toEqual({ message: 'Success' });
  });

  it('disallows purchases outside of business hours', () => {
    // 업무 시간 외로 시간을 설정합니다.
    const date = new Date(2000, 1, 1, 19);
    vi.setSystemTime(date);

    // Date.now()를 호출하면 위에 설정된 날짜가 반환됩니다.
    expect(purchase()).toEqual({ message: 'Error' });
  });
});

함수 ​

함수 모킹은 _스파이(spying) 및 목(mocking)_의 두 가지 범주로 구분할 수 있습니다.

때로는 특정 함수가 호출되었는지(그리고 어떤 인수가 전달되었는지)만 확인하면 됩니다. 이러한 경우 스파이 기능만으로 충분하며, vi.spyOn()을 직접 사용할 수 있습니다(여기에서 자세히 읽어보기).

그러나 스파이는 함수를 스파이하는 데만 도움이 되며, 해당 함수의 구현을 변경할 수는 없습니다. 함수의 가짜(또는 목) 버전을 만들어야 하는 경우 vi.fn()을 사용할 수 있습니다(여기에서 자세히 읽어보기).

함수 모킹을 위해 기본적으로 Tinyspy를 사용하지만, jest 호환성을 위해 자체 래퍼를 사용합니다. vi.fn()과 vi.spyOn()은 동일한 메서드를 공유하지만, vi.fn()의 반환 결과만 호출할 수 있습니다.

예시 ​

js
import { afterEach, describe, expect, it, vi } from 'vitest';

const messages = {
  items: [
    { message: 'Simple test message', from: 'Testman' },
    // ...
  ],
  getLatest, // 지원되는 경우 `getter 또는 setter`일 수도 있습니다.
};

function getLatest(index = messages.items.length - 1) {
  return messages.items[index];
}

describe('reading messages', () => {
  afterEach(() => {
    vi.restoreAllMocks();
  });

  it('should get the latest message with a spy', () => {
    const spy = vi.spyOn(messages, 'getLatest');
    expect(spy.getMockName()).toEqual('getLatest');

    expect(messages.getLatest()).toEqual(
      messages.items[messages.items.length - 1]
    );

    expect(spy).toHaveBeenCalledTimes(1);

    spy.mockImplementationOnce(() => 'access-restricted');
    expect(messages.getLatest()).toEqual('access-restricted');

    expect(spy).toHaveBeenCalledTimes(2);
  });

  it('should get with a mock', () => {
    const mock = vi.fn().mockImplementation(getLatest);

    expect(mock()).toEqual(messages.items[messages.items.length - 1]);
    expect(mock).toHaveBeenCalledTimes(1);

    mock.mockImplementationOnce(() => 'access-restricted');
    expect(mock()).toEqual('access-restricted');

    expect(mock).toHaveBeenCalledTimes(2);

    expect(mock()).toEqual(messages.items[messages.items.length - 1]);
    expect(mock).toHaveBeenCalledTimes(3);
  });
});

더 보기 ​

  • Jest의 Mock 함수

전역 ​

jsdom 또는 node에 없는 전역 변수는 vi.stubGlobal 헬퍼를 사용하여 모킹할 수 있습니다. 이 헬퍼는 전역 변수의 값을 globalThis 객체에 할당합니다.

ts
import { vi } from 'vitest';

const IntersectionObserverMock = vi.fn(() => ({
  disconnect: vi.fn(),
  observe: vi.fn(),
  takeRecords: vi.fn(),
  unobserve: vi.fn(),
}));

vi.stubGlobal('IntersectionObserver', IntersectionObserverMock);

// 이제 `IntersectionObserver` 또는 `window.IntersectionObserver`로 액세스할 수 있습니다.

모듈 ​

모의 모듈은 다른 코드에서 호출되는 타사 라이브러리를 대상으로 하여 인수, 출력 또는 구현 재선언까지 테스트할 수 있도록 합니다.

더 자세한 API 설명은 vi.mock() API 섹션을 참조하세요.

자동 모킹 알고리즘 ​

코드가 모의 모듈을 가져오는데, 이 모듈에 대한 __mocks__ 파일이나 factory가 없는 경우, Vitest는 모듈 자체를 호출하고 모든 내보내기를 모킹하여 해당 모듈을 목(mock) 처리합니다.

다음 원칙이 적용됩니다.

  • 모든 배열은 비워집니다.
  • 모든 기본형 및 컬렉션은 동일하게 유지됩니다.
  • 모든 객체는 깊게 복제됩니다.
  • 클래스의 모든 인스턴스와 해당 프로토타입은 깊게 복제됩니다.

가상 모듈 ​

Vitest는 Vite 가상 모듈의 목(mock) 처리를 지원합니다. Jest에서 가상 모듈을 처리하는 방식과는 다르게 동작합니다. vi.mock 함수에 virtual: true를 전달하는 대신, Vite에 모듈이 존재한다고 알려야 합니다. 그렇지 않으면 파싱 시 오류가 발생합니다. 몇 가지 방법으로 이를 수행할 수 있습니다.

  1. 별칭 제공
ts
import { defineConfig } from 'vitest/config';
import { resolve } from 'node:path';
export default defineConfig({
  test: {
    alias: {
      '$app/forms': resolve('./mocks/forms.js'),
    },
  },
});
  1. 가상 모듈을 해결하는 플러그인 제공
ts
import { defineConfig } from 'vitest/config';
export default defineConfig({
  plugins: [
    {
      name: 'virtual-modules',
      resolveId(id) {
        if (id === '$app/forms') {
          return 'virtual:$app/forms';
        }
      },
    },
  ],
});

두 번째 접근 방식의 장점은 다양한 가상 엔트리포인트를 동적으로 생성할 수 있다는 것입니다. 여러 가상 모듈을 단일 파일로 매핑하면 모든 모듈이 vi.mock의 영향을 받으므로 고유한 식별자를 사용해야 합니다.

목(mock) 사용 시 주의사항 ​

동일한 파일의 다른 메서드 내부에서 호출되는 메서드에 대한 호출을 모킹하는 것은 불가능하다는 점에 유의하십시오. 예를 들어, 다음 코드에서:

ts
export function foo() {
  return 'foo';
}

export function foobar() {
  return `${foo()}bar`;
}

foo 메서드는 직접 참조되므로 외부에서 목(mock) 처리할 수 없습니다. 따라서 이 코드는 foobar 내부의 foo 호출에는 영향을 미치지 않지만, 다른 모듈의 foo 호출에는 영향을 줍니다.

ts
import { vi } from 'vitest';
import * as mod from './foobar.js';

// 이것은 원본 모듈 외부의 "foo"에만 영향을 미칩니다.
vi.spyOn(mod, 'foo');
vi.mock('./foobar.js', async importOriginal => {
  return {
    ...(await importOriginal<typeof import('./foobar.js')>()),
    // 이것은 원본 모듈 외부의 "foo"에만 영향을 미칩니다.
    foo: () => 'mocked',
  };
});

foobar 메서드에 직접 구현을 제공하여 이 동작을 확인할 수 있습니다.

ts
import * as mod from './foobar.js';

vi.spyOn(mod, 'foo');

// 내보낸 foo는 모의 메서드를 참조합니다.
mod.foobar(mod.foo);
ts
export function foo() {
  return 'foo';
}

export function foobar(injectedFoo) {
  return injectedFoo === foo; // false
}

이것은 의도된 동작입니다. 일반적으로 이러한 방식으로 모킹이 사용될 때 좋지 않은 코드의 징후입니다. 코드를 여러 파일로 리팩토링하거나 의존성 주입과 같은 기술을 사용하여 애플리케이션 아키텍처를 개선하는 것을 고려하십시오.

예시 ​

js
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { Client } from 'pg';
import { failure, success } from './handlers.js';

// 할 일 목록 가져오기
export async function getTodos(event, context) {
  const client = new Client({
    // ...clientOptions
  });

  await client.connect();

  try {
    const result = await client.query('SELECT * FROM todos;');

    client.end();

    return success({
      message: `${result.rowCount} item(s) returned`,
      data: result.rows,
      status: true,
    });
  } catch (e) {
    console.error(e.stack);

    client.end();

    return failure({ message: e, status: false });
  }
}

vi.mock('pg', () => {
  const Client = vi.fn();
  Client.prototype.connect = vi.fn();
  Client.prototype.query = vi.fn();
  Client.prototype.end = vi.fn();

  return { Client };
});

vi.mock('./handlers.js', () => {
  return {
    success: vi.fn(),
    failure: vi.fn(),
  };
});

describe('get a list of todo items', () => {
  let client;

  beforeEach(() => {
    client = new Client();
  });

  afterEach(() => {
    vi.clearAllMocks();
  });

  it('should return items successfully', async () => {
    client.query.mockResolvedValueOnce({ rows: [], rowCount: 0 });

    await getTodos();

    expect(client.connect).toBeCalledTimes(1);
    expect(client.query).toBeCalledWith('SELECT * FROM todos;');
    expect(client.end).toBeCalledTimes(1);

    expect(success).toBeCalledWith({
      message: '0 item(s) returned',
      data: [],
      status: true,
    });
  });

  it('should throw an error', async () => {
    const mError = new Error('Unable to retrieve rows');
    client.query.mockRejectedValueOnce(mError);

    await getTodos();

    expect(client.connect).toBeCalledTimes(1);
    expect(client.query).toBeCalledWith('SELECT * FROM todos;');
    expect(client.end).toBeCalledTimes(1);
    expect(failure).toBeCalledWith({ message: mError, status: false });
  });
});

파일 시스템 ​

파일 시스템을 모킹하면 테스트가 실제 파일 시스템에 의존하지 않으므로 테스트가 더 안정적이고 예측 가능하게 됩니다. 이러한 격리는 이전 테스트의 부작용을 방지하는 데 기여합니다. 권한 문제, 디스크 공간 부족 시나리오 또는 읽기/쓰기 오류와 같이 실제 파일 시스템으로는 재현하기 어렵거나 불가능할 수 있는 오류 조건 및 엣지 케이스를 테스트할 수 있습니다.

Vitest는 기본적으로 파일 시스템 모킹 API를 제공하지 않습니다. vi.mock을 사용하여 fs 모듈을 수동으로 모킹할 수 있지만 유지 관리가 어렵습니다. 대신 memfs를 사용하는 것을 권장합니다. memfs는 실제 디스크를 건드리지 않고 파일 시스템 작업을 시뮬레이션하는 인메모리 파일 시스템을 생성합니다. 이 접근 방식은 빠르고 안전하며 실제 파일 시스템에 대한 잠재적인 부작용을 방지합니다.

예시 ​

모든 fs 호출을 memfs로 자동 리디렉션하려면 프로젝트 루트에 __mocks__/fs.cjs 및 __mocks__/fs/promises.cjs 파일을 생성할 수 있습니다.

ts
// `import`를 사용할 수도 있지만,
// 모든 내보내기는 명시적으로 정의되어야 합니다.

const { fs } = require('memfs');
module.exports = fs;
ts
// `import`를 사용할 수도 있지만,
// 모든 내보내기는 명시적으로 정의되어야 합니다.

const { fs } = require('memfs');
module.exports = fs.promises;
ts
import { readFileSync } from 'node:fs';

export function readHelloWorld(path) {
  return readFileSync(path, 'utf-8');
}
ts
import { beforeEach, expect, it, vi } from 'vitest';
import { fs, vol } from 'memfs';
import { readHelloWorld } from './read-hello-world.js';

// Vitest에 __mocks__ 폴더의 fs 모의를 사용하도록 지시합니다.
// fs가 항상 모의되어야 하는 경우 설정 파일에서 수행할 수 있습니다.
vi.mock('node:fs');
vi.mock('node:fs/promises');

beforeEach(() => {
  // 인메모리 fs의 상태를 재설정합니다.
  vol.reset();
});

it('should return correct text', () => {
  const path = '/hello-world.txt';
  fs.writeFileSync(path, 'hello world');

  const text = readHelloWorld(path);
  expect(text).toBe('hello world');
});

it('can return a value multiple times', () => {
  // vol.fromJSON을 사용하여 여러 파일을 정의할 수 있습니다.
  vol.fromJSON(
    {
      './dir1/hw.txt': 'hello dir1',
      './dir2/hw.txt': 'hello dir2',
    },
    // 기본 cwd
    '/tmp'
  );

  expect(readHelloWorld('/tmp/dir1/hw.txt')).toBe('hello dir1');
  expect(readHelloWorld('/tmp/dir2/hw.txt')).toBe('hello dir2');
});

요청 ​

Vitest는 Node에서 실행되므로 네트워크 요청을 모킹하는 것은 까다롭습니다. 이는 웹 API를 사용할 수 없으므로 네트워크 동작을 모방할 무언가가 필요하기 때문입니다. 이를 위해 Mock Service Worker를 사용하는 것을 권장합니다. 이 라이브러리는 http, WebSocket, GraphQL 네트워크 요청을 모킹할 수 있으며 프레임워크에 독립적입니다.

Mock Service Worker (MSW)는 테스트가 수행하는 요청을 가로채는 방식으로 작동하므로 애플리케이션 코드를 변경하지 않고도 사용할 수 있습니다. 브라우저에서는 Service Worker API를 사용합니다. Node.js 및 Vitest의 경우 @mswjs/interceptors 라이브러리를 사용합니다. MSW에 대해 자세히 알아보려면 소개를 읽어보세요.

구성 ​

설정 파일에서 다음과 같이 사용할 수 있습니다.

js
import { afterAll, afterEach, beforeAll } from 'vitest';
import { setupServer } from 'msw/node';
import { http, HttpResponse } from 'msw';

const posts = [
  {
    userId: 1,
    id: 1,
    title: 'first post title',
    body: 'first post body',
  },
  // ...
];

export const restHandlers = [
  http.get('https://rest-endpoint.example/path/to/posts', () => {
    return HttpResponse.json(posts);
  }),
];

const server = setupServer(...restHandlers);

// 모든 테스트 전에 서버 시작
beforeAll(() => server.listen({ onUnhandledRequest: 'error' }));

// 모든 테스트 후에 서버 닫기
afterAll(() => server.close());

// 테스트 간 독립성을 위해 각 테스트 후에 핸들러 재설정
afterEach(() => server.resetHandlers());
js
import { afterAll, afterEach, beforeAll } from 'vitest';
import { setupServer } from 'msw/node';
import { graphql, HttpResponse } from 'msw';

const posts = [
  {
    userId: 1,
    id: 1,
    title: 'first post title',
    body: 'first post body',
  },
  // ...
];

const graphqlHandlers = [
  graphql.query('ListPosts', () => {
    return HttpResponse.json({
      data: { posts },
    });
  }),
];

const server = setupServer(...graphqlHandlers);

// 모든 테스트 전에 서버 시작
beforeAll(() => server.listen({ onUnhandledRequest: 'error' }));

// 모든 테스트 후에 서버 닫기
afterAll(() => server.close());

// 테스트 간 독립성을 위해 각 테스트 후에 핸들러 재설정
afterEach(() => server.resetHandlers());
js
import { afterAll, afterEach, beforeAll } from 'vitest';
import { setupServer } from 'msw/node';
import { ws } from 'msw';

const chat = ws.link('wss://chat.example.com');

const wsHandlers = [
  chat.addEventListener('connection', ({ client }) => {
    client.addEventListener('message', event => {
      console.log('Received message from client:', event.data);
      // 수신된 메시지를 클라이언트에 다시 에코합니다.
      client.send(`Server received: ${event.data}`);
    });
  }),
];

const server = setupServer(...wsHandlers);

// 모든 테스트 전에 서버 시작
beforeAll(() => server.listen({ onUnhandledRequest: 'error' }));

// 모든 테스트 후에 서버 닫기
afterAll(() => server.close());

// 테스트 간 독립성을 위해 각 테스트 후에 핸들러 재설정
afterEach(() => server.resetHandlers());

onUnhandledRequest: 'error'로 서버를 구성하면 해당 요청 핸들러가 없는 요청이 있을 때마다 오류가 발생합니다.

더 보기 ​

MSW에는 훨씬 더 많은 기능이 있습니다. 쿠키 및 쿼리 매개변수에 액세스하고, 모의 오류 응답을 정의하는 등 다양한 작업을 수행할 수 있습니다! MSW로 할 수 있는 모든 것을 보려면 문서를 읽어보세요.

타이머 ​

타임아웃 또는 인터벌이 포함된 코드를 테스트할 때, 테스트가 대기하거나 타임아웃되는 것을 방지하고 setTimeout 및 setInterval 호출을 모킹하는 "가짜" 타이머를 사용하여 테스트 속도를 높일 수 있습니다.

더 자세한 API 설명은 vi.useFakeTimers API 섹션을 참조하세요.

예시 ​

js
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';

function executeAfterTwoHours(func) {
  setTimeout(func, 1000 * 60 * 60 * 2); // 2시간
}

function executeEveryMinute(func) {
  setInterval(func, 1000 * 60); // 1분
}

const mock = vi.fn(() => console.log('executed'));

describe('delayed execution', () => {
  beforeEach(() => {
    vi.useFakeTimers();
  });
  afterEach(() => {
    vi.restoreAllMocks();
  });
  it('should execute the function', () => {
    executeAfterTwoHours(mock);
    vi.runAllTimers();
    expect(mock).toHaveBeenCalledTimes(1);
  });
  it('should not execute the function', () => {
    executeAfterTwoHours(mock);
    // 2ms 진행해도 함수가 트리거되지 않습니다.
    vi.advanceTimersByTime(2);
    expect(mock).not.toHaveBeenCalled();
  });
  it('should execute every minute', () => {
    executeEveryMinute(mock);
    vi.advanceTimersToNextTimer();
    expect(mock).toHaveBeenCalledTimes(1);
    vi.advanceTimersToNextTimer();
    expect(mock).toHaveBeenCalledTimes(2);
  });
});

클래스 ​

단일 vi.fn 호출로 전체 클래스를 모킹할 수 있습니다. 모든 클래스는 함수이기도 하므로 이 방법은 기본적으로 작동합니다. 현재 Vitest는 new 키워드를 지원하지 않으므로 함수의 본문에서 new.target은 항상 undefined라는 점에 유의하십시오.

ts
class Dog {
  name: string;

  constructor(name: string) {
    this.name = name;
  }

  static getType(): string {
    return 'animal';
  }

  greet = (): string => {
    return `Hi! My name is ${this.name}!`;
  };

  speak(): string {
    return 'bark!';
  }

  isHungry() {}
  feed() {}
}

이 클래스를 ES5 함수로 다시 만들 수 있습니다.

ts
const Dog = vi.fn(function (name) {
  this.name = name;
  // 생성자에서 인스턴스 메서드를 모킹합니다. 각 인스턴스는 자체 스파이를 가지게 됩니다.
  this.greet = vi.fn(() => `Hi! My name is ${this.name}!`);
});

// 정적 메서드는 함수에 직접 목(mock) 처리되며,
// 클래스의 인스턴스에는 목(mock) 처리되지 않습니다.
Dog.getType = vi.fn(() => 'mocked animal');

// 클래스의 모든 인스턴스에서 "speak" 및 "feed" 메서드를 모킹합니다.
// 모든 `new Dog()` 인스턴스는 이러한 스파이를 상속하고 공유합니다.
Dog.prototype.speak = vi.fn(() => 'loud bark!');
Dog.prototype.feed = vi.fn();

WARNING

생성자 함수에서 비기본형이 반환되면 해당 값이 새 표현식의 결과가 됩니다. 이 경우 [[Prototype]]이 올바르게 바인딩되지 않을 수 있습니다.

ts
const CorrectDogClass = vi.fn(function (name) {
  this.name = name;
});

const IncorrectDogClass = vi.fn(name => ({
  name,
}));

const Marti = new CorrectDogClass('Marti');
const Newt = new IncorrectDogClass('Newt');

Marti instanceof CorrectDogClass; // ✅ true
Newt instanceof IncorrectDogClass; // ❌ false!

언제 사용해야 할까요?

일반적으로 클래스가 다른 모듈에서 다시 내보내지는 경우 모듈 팩토리 내부에서 다음과 같이 클래스를 다시 만듭니다.

ts
import { Dog } from './dog.js';

vi.mock(import('./dog.js'), () => {
  const Dog = vi.fn();
  Dog.prototype.feed = vi.fn();
  // ... 기타 모의
  return { Dog };
});

이 메서드는 동일한 인터페이스를 받아들이는 함수에 클래스 인스턴스를 전달하는 데도 사용할 수 있습니다.

ts
function feed(dog: Dog) {
  // ...
}
ts
import { expect, test, vi } from 'vitest';
import { feed } from '../src/feed.js';

const Dog = vi.fn();
Dog.prototype.feed = vi.fn();

test('can feed dogs', () => {
  const dogMax = new Dog('Max');

  feed(dogMax);

  expect(dogMax.feed).toHaveBeenCalled();
  expect(dogMax.isHungry()).toBe(false);
});

이제 Dog 클래스의 새 인스턴스를 생성하면 speak 메서드(및 feed 및 greet)가 이미 모킹됩니다.

ts
const Cooper = new Dog('Cooper');
Cooper.speak(); // loud bark!
Cooper.greet(); // Hi! My name is Cooper!

// 내장된 어설션을 사용하여 호출의 유효성을 검증할 수 있습니다.
expect(Cooper.speak).toHaveBeenCalled();
expect(Cooper.greet).toHaveBeenCalled();

const Max = new Dog('Max');

// 프로토타입에 정의된 메서드는 모든 인스턴스에서 공유됩니다.
expect(Max.speak).toHaveBeenCalled();
expect(Max.greet).not.toHaveBeenCalled();

특정 인스턴스의 반환 값을 재할당할 수 있습니다.

ts
const dog = new Dog('Cooper');

// "vi.mocked"는 타입 도우미입니다.
// TypeScript는 Dog가 목(mock) 클래스인지 알지 못하므로,
// 함수가 모의인지 유효성 검사를 수행하지 않고
// 모든 함수를 MockInstance<T> 타입으로 래핑합니다.
vi.mocked(dog.speak).mockReturnValue('woof woof');

dog.speak(); // woof woof

속성을 모킹하려면 vi.spyOn(dog, 'name', 'get') 메서드를 사용할 수 있습니다. 이렇게 하면 모킹된 속성에 스파이 검증을 사용할 수 있습니다.

ts
const dog = new Dog('Cooper');

const nameSpy = vi.spyOn(dog, 'name', 'get').mockReturnValue('Max');

expect(dog.name).toBe('Max');
expect(nameSpy).toHaveBeenCalledTimes(1);

TIP

동일한 메서드를 사용하여 getter 및 setter를 스파이할 수도 있습니다.

참고 자료 ​

INFO

아래 예시에서 vi는 vitest에서 직접 가져온 것입니다. 설정에서 globals를 true로 설정하면 전역으로도 사용할 수 있습니다.

나는…

내보낸 변수 모킹 ​

js
export const getter = 'variable';
ts
import * as exports from './example.js';

vi.spyOn(exports, 'getter', 'get').mockReturnValue('mocked');

내보낸 함수 모킹 ​

  1. vi.mock 예시:

WARNING

vi.mock 호출은 파일의 맨 위로 호이스팅된다는 점을 유의하십시오. 항상 모든 import보다 먼저 실행됩니다.

ts
export function method() {}
ts
import { method } from './example.js';

vi.mock('./example.js', () => ({
  method: vi.fn(),
}));
  1. vi.spyOn 예시:
ts
import * as exports from './example.js';

vi.spyOn(exports, 'method').mockImplementation(() => {});

내보낸 클래스 구현 모킹 ​

  1. vi.mock 및 .prototype 예시:
ts
export class SomeClass {}
ts
import { SomeClass } from './example.js';

vi.mock(import('./example.js'), () => {
  const SomeClass = vi.fn();
  SomeClass.prototype.someMethod = vi.fn();
  return { SomeClass };
});
// SomeClass.mock.instances는 SomeClass의 인스턴스를 포함합니다.
  1. vi.spyOn 예시:
ts
import * as mod from './example.js';

const SomeClass = vi.fn();
SomeClass.prototype.someMethod = vi.fn();

vi.spyOn(mod, 'SomeClass').mockImplementation(SomeClass);

함수에서 반환된 객체 스파이 ​

  1. 캐시 사용 예시:
ts
export function useObject() {
  return { method: () => true };
}
ts
import { useObject } from './example.js';

const obj = useObject();
obj.method();
ts
import { useObject } from './example.js';

vi.mock(import('./example.js'), () => {
  let _cache;
  const useObject = () => {
    if (!_cache) {
      _cache = {
        method: vi.fn(),
      };
    }
    // 이제 useObject()가 호출될 때마다
    // 동일한 객체 참조를 반환합니다.
    return _cache;
  };
  return { useObject };
});

const obj = useObject();
// obj.method는 해당 경로(some-path) 내부에서 호출되었습니다.
expect(obj.method).toHaveBeenCalled();

모듈의 일부 모킹 ​

ts
import { mocked, original } from './some-path.js';

vi.mock(import('./some-path.js'), async importOriginal => {
  const mod = await importOriginal();
  return {
    ...mod,
    mocked: vi.fn(),
  };
});
original(); // 원본 동작을 가집니다.
mocked(); // 스파이 함수입니다.

WARNING

이것은 외부 액세스만 목(mock) 처리된다는 점을 잊지 마세요. 이 예시에서 original이 내부적으로 mocked를 호출하면, 목(mock) 팩토리가 아닌 모듈에 정의된 함수를 항상 호출합니다.

현재 날짜 모킹 ​

Date의 시간을 모킹하려면 vi.setSystemTime 헬퍼 함수를 사용할 수 있습니다. 이 값은 다른 테스트 간에 자동으로 초기화되지 않습니다.

vi.useFakeTimers를 사용하면 Date의 시간도 변경된다는 점에 유의하십시오.

ts
const mockDate = new Date(2022, 0, 1);
vi.setSystemTime(mockDate);
const now = new Date();
expect(now.valueOf()).toBe(mockDate.valueOf());
// 모의 시간 재설정
vi.useRealTimers();

전역 변수 모킹 ​

globalThis에 값을 할당하거나 vi.stubGlobal 헬퍼를 사용하여 전역 변수를 설정할 수 있습니다. vi.stubGlobal을 사용할 때, unstubGlobals 구성 옵션을 활성화하거나 vi.unstubAllGlobals를 호출하지 않으면 다른 테스트 간에 자동으로 초기화되지 않습니다.

ts
vi.stubGlobal('__VERSION__', '1.0.0');
expect(__VERSION__).toBe('1.0.0');

import.meta.env 모킹 ​

  1. 환경 변수를 변경하려면 새 값을 할당하면 됩니다.

WARNING

환경 변수 값은 다른 테스트 간에 자동으로 초기화되지 않습니다.

ts
import { beforeEach, expect, it } from 'vitest';

// 테스트 실행 전 "VITE_ENV"는 "test" 값입니다.
const originalViteEnv = import.meta.env.VITE_ENV;

beforeEach(() => {
  import.meta.env.VITE_ENV = originalViteEnv;
});

it('changes value', () => {
  import.meta.env.VITE_ENV = 'staging';
  expect(import.meta.env.VITE_ENV).toBe('staging');
});
  1. 값을 자동으로 재설정하려면 unstubEnvs 구성 옵션을 활성화한 상태에서 vi.stubEnv 헬퍼를 사용하거나 (beforeEach 훅에서 vi.unstubAllEnvs를 수동으로 호출):
ts
import { expect, it, vi } from 'vitest';

// 테스트 실행 전 "VITE_ENV"는 "test" 값입니다.
import.meta.env.VITE_ENV === 'test';

it('changes value', () => {
  vi.stubEnv('VITE_ENV', 'staging');
  expect(import.meta.env.VITE_ENV).toBe('staging');
});

it('the value is restored before running an other test', () => {
  expect(import.meta.env.VITE_ENV).toBe('test');
});
ts
export default defineConfig({
  test: {
    unstubEnvs: true,
  },
});
Pager
이전스냅샷
다음병렬 처리

MIT 라이선스 하에 배포되었습니다.

Copyright (c) 2021-Present Vitest Team

https://vitest.dev/guide/mocking

MIT 라이선스 하에 배포되었습니다.

Copyright (c) 2021-Present Vitest Team