Skip to content
Vitest 2
Main Navigation 가이드API구성브라우저 모드고급
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 UI

소스 내 테스트

테스트 컨텍스트

테스트 환경

Matcher 확장하기

IDE 통합

디버깅

다른 테스트 러너와의 비교

마이그레이션 가이드

일반적인 오류

Profiling Test Performance

성능 향상

이 페이지에서

Mocking ​

테스트를 작성할 때, 내부 또는 외부 서비스의 "가짜" 버전을 만들어야 하는 경우가 있습니다. 이를 일반적으로 **모킹(mocking)**이라고 합니다. Vitest는 vi 헬퍼를 통해 유용한 유틸리티 함수를 제공합니다. import { vi } from 'vitest'를 사용하여 가져오거나, 전역 설정이 활성화된 경우 전역적으로 접근할 수 있습니다.

WARNING

모의 상태 변경이 테스트 간에 유지되지 않도록 하려면 각 테스트 실행 전후에 모의를 지우거나 복원하는 것을 항상 기억하십시오! 자세한 내용은 mockReset 문서를 참조하십시오.

바로 핵심으로 들어가고 싶다면 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, // 지원되는 경우 게터 또는 세터일 수도 있습니다.
};

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는 모듈 자체를 호출하고 모든 내보내기를 모의 처리합니다.

다음 원칙이 적용됩니다.

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

가상 모듈 ​

Vitest는 Vite 가상 모듈 모킹을 지원합니다. Jest에서 가상 모듈이 처리되는 방식과는 다르게 작동합니다. vi.mock 함수에 virtual: true를 전달하는 대신, Vite에 해당 모듈이 존재함을 알려야 합니다. 그렇지 않으면 파싱 중에 실패합니다. 몇 가지 방법으로 이를 수행할 수 있습니다.

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

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

모킹의 함정 ​

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

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

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

foo 메서드는 직접 참조되므로 외부에서 모킹할 수 없습니다. 따라서 이 코드는 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
// foobar.test.js
import * as mod from './foobar.js';

vi.spyOn(mod, 'foo');

// 내보낸 foo는 모의 메서드를 참조합니다.
mod.foobar(mod.foo);
ts
// foobar.js
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
// read-hello-world.js
import { readFileSync } from 'node:fs';

export function readHelloWorld(path) {
  return readFileSync(path);
}
ts
// hello-world.test.js
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를 사용하는 것을 권장합니다. 이 라이브러리는 REST 및 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 { graphql, 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 graphqlHandlers = [
  graphql.query('ListPosts', () => {
    return HttpResponse.json({
      data: { posts },
    });
  }),
];

const server = setupServer(...restHandlers, ...graphqlHandlers);

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

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

// 각 테스트 후에 핸들러를 재설정합니다. (테스트 격리에 중요)
afterEach(() => server.resetHandlers());

onUnhandleRequest: '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';
  }

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

  isHungry() {}
  feed() {}
}

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

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

// 정적 메서드는 클래스의 인스턴스가 아닌 함수에 직접 모킹됩니다.
Dog.getType = vi.fn(() => 'mocked animal');

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

언제 사용해야 할까요?

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

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

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

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

ts
// ./src/feed.ts
function feed(dog: Dog) {
  // ...
}

// ./tests/dog.test.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)가 이미 모의됩니다.

ts
const dog = new Dog('Cooper');
dog.speak(); // loud bark!

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

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

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

// "vi.mocked"는 타입 헬퍼입니다.
// TypeScript는 Dog가 모의 클래스인지 알지 못하기 때문에,
// 함수가 모의인지 유효성을 검사하지 않고
// 모든 함수를 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

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

치트 시트 ​

INFO

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

나는…

내보낸 변수 모킹 ​

js
// some-path.js
export const getter = 'variable';
ts
// some-path.test.ts
import * as exports from './some-path.js';

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

내보낸 함수 모킹 ​

  1. vi.mock 예시:

WARNING

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

ts
// ./some-path.js
export function method() {}
ts
import { method } from './some-path.js';

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

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

내보낸 클래스 구현 모킹 ​

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

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

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

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

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

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

const obj = useObject();
obj.method();
ts
// useObject.test.js
import { useObject } from './some-path.js';

vi.mock(import('./some-path.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

이것은 외부 접근만 모킹한다는 점을 잊지 마십시오. 이 예시에서 original이 내부적으로 mocked를 호출하면 항상 모킹 팩토리가 아닌 원본 모듈의 함수를 호출합니다.

현재 날짜 모킹 ​

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';

// beforeEach 훅에서 수동으로 재설정할 수 있습니다.
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('다른 테스트를 실행하기 전에 값이 복원됩니다.', () => {
  expect(import.meta.env.VITE_ENV).toBe('test');
});
ts
// vitest.config.ts
export default defineConfig({
  test: {
    unstubEnvs: true,
  },
});
Pager
이전스냅샷
다음타입 테스트

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

Copyright (c) 2024 Mithril Contributors

https://v2.vitest.dev/guide/mocking

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

Copyright (c) 2024 Mithril Contributors