Mocking
테스트를 작성할 때, 내부 또는 외부 서비스의 "가짜" 버전을 만들어야 하는 경우가 있습니다. 이를 일반적으로 **모킹(mocking)**이라고 합니다. Vitest는 vi
헬퍼를 통해 유용한 유틸리티 함수를 제공합니다. import { vi } from 'vitest'
를 사용하여 가져오거나, 전역 설정이 활성화된 경우 전역적으로 접근할 수 있습니다.
WARNING
모의 상태 변경이 테스트 간에 유지되지 않도록 하려면 각 테스트 실행 전후에 모의를 지우거나 복원하는 것을 항상 기억하십시오! 자세한 내용은 mockReset
문서를 참조하십시오.
바로 핵심으로 들어가고 싶다면 API 섹션을 확인하고, 그렇지 않다면 계속 읽으면서 모킹의 세계를 더 깊이 탐구하십시오.
날짜
때로는 테스트 시 일관성을 보장하기 위해 날짜를 제어할 필요가 있습니다. Vitest는 타이머와 시스템 날짜를 조작하기 위해 @sinonjs/fake-timers
패키지를 사용합니다. 특정 API에 대한 자세한 내용은 여기에서 확인할 수 있습니다.
예시
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()
의 반환 결과만 호출 가능합니다.
예시
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);
});
});
더 보기
전역
jsdom
또는 node
에 없는 전역 변수는 vi.stubGlobal
헬퍼를 사용하여 모킹할 수 있습니다. 이 헬퍼는 전역 변수의 값을 globalThis
객체에 설정합니다.
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에 해당 모듈이 존재함을 알려야 합니다. 그렇지 않으면 파싱 중에 실패합니다. 몇 가지 방법으로 이를 수행할 수 있습니다.
- 별칭 제공
// vitest.config.js
export default {
test: {
alias: {
'$app/forms': resolve('./mocks/forms.js'),
},
},
};
- 가상 모듈을 해결하는 플러그인 제공
// vitest.config.js
export default {
plugins: [
{
name: 'virtual-modules',
resolveId(id) {
if (id === '$app/forms') {
return 'virtual:$app/forms';
}
},
},
],
};
두 번째 접근 방식의 장점은 다양한 가상 진입점을 동적으로 생성할 수 있다는 것입니다. 여러 가상 모듈을 단일 파일로 리디렉션하면 모든 모듈이 vi.mock
에 의해 영향을 받으므로 고유한 식별자를 사용해야 합니다.
모킹의 함정
동일한 파일 내의 다른 메서드에서 호출되는 메서드를 모킹하는 것은 불가능하다는 점에 유의하십시오. 예를 들어, 다음 코드에서:
export function foo() {
return 'foo';
}
export function foobar() {
return `${foo()}bar`;
}
foo
메서드는 직접 참조되므로 외부에서 모킹할 수 없습니다. 따라서 이 코드는 foobar
내부의 foo
호출에는 영향을 미치지 않지만 (다른 모듈의 foo
호출에는 영향을 미칩니다):
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
메서드에 직접 구현을 제공하여 이 동작을 확인할 수 있습니다.
// foobar.test.js
import * as mod from './foobar.js';
vi.spyOn(mod, 'foo');
// 내보낸 foo는 모의 메서드를 참조합니다.
mod.foobar(mod.foo);
// foobar.js
export function foo() {
return 'foo';
}
export function foobar(injectedFoo) {
return injectedFoo === foo; // false
}
이것은 의도된 동작입니다. 일반적으로 이러한 방식으로 모킹이 관련될 때 나쁜 코드의 징후입니다. 코드를 여러 파일로 리팩토링하거나 의존성 주입과 같은 기술을 사용하여 애플리케이션 아키텍처를 개선하는 것을 고려하십시오.
예시
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
파일을 생성할 수 있습니다.
// `import`를 사용할 수도 있지만,
// 모든 내보내기는 명시적으로 정의되어야 합니다.
const { fs } = require('memfs');
module.exports = fs;
// `import`를 사용할 수도 있지만,
// 모든 내보내기는 명시적으로 정의되어야 합니다.
const { fs } = require('memfs');
module.exports = fs.promises;
// read-hello-world.js
import { readFileSync } from 'node:fs';
export function readHelloWorld(path) {
return readFileSync(path);
}
// 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에 대해 자세히 알아보려면 소개를 읽어보십시오.
구성
설정 파일에서 다음과 같이 사용할 수 있습니다.
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 섹션을 참조하십시오.
예시
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
라는 점에 유의하십시오.
class Dog {
name: string;
constructor(name: string) {
this.name = name;
}
static getType(): string {
return 'animal';
}
speak(): string {
return 'bark!';
}
isHungry() {}
feed() {}
}
이 클래스를 ES5 함수로 다시 만들 수 있습니다.
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();
언제 사용해야 할까요?
일반적으로 클래스가 다른 모듈에서 다시 내보내지는 경우 모듈 팩토리 내에서 다음과 같이 클래스를 재생성합니다.
import { Dog } from './dog.js';
vi.mock(import('./dog.js'), () => {
const Dog = vi.fn();
Dog.prototype.feed = vi.fn();
// ... 기타 모의
return { Dog };
});
이 메서드는 동일한 인터페이스를 허용하는 함수에 클래스 인스턴스를 전달하는 데도 사용할 수 있습니다.
// ./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
)가 이미 모의됩니다.
const dog = new Dog('Cooper');
dog.speak(); // loud bark!
// 내장된 어설션을 사용하여 호출의 유효성을 확인할 수 있습니다.
expect(dog.speak).toHaveBeenCalled();
특정 인스턴스의 반환 값을 재할당할 수 있습니다.
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')
메서드를 사용할 수 있습니다. 이렇게 하면 모킹된 속성에 스파이 어설션을 사용할 수 있습니다.
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
로 설정하면 전역적으로 사용할 수도 있습니다.
나는…
내보낸 변수 모킹
// some-path.js
export const getter = 'variable';
// some-path.test.ts
import * as exports from './some-path.js';
vi.spyOn(exports, 'getter', 'get').mockReturnValue('mocked');
내보낸 함수 모킹
vi.mock
예시:
WARNING
vi.mock
호출은 파일의 맨 위로 호이스팅된다는 점을 잊지 마십시오. 항상 모든 import보다 먼저 실행됩니다.
// ./some-path.js
export function method() {}
import { method } from './some-path.js';
vi.mock('./some-path.js', () => ({
method: vi.fn(),
}));
vi.spyOn
예시:
import * as exports from './some-path.js';
vi.spyOn(exports, 'method').mockImplementation(() => {});
내보낸 클래스 구현 모킹
vi.mock
및.prototype
예시:
// ./some-path.ts
export class SomeClass {}
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를 포함합니다.
vi.spyOn
예시:
import * as mod from './some-path.js';
const SomeClass = vi.fn();
SomeClass.prototype.someMethod = vi.fn();
vi.spyOn(mod, 'SomeClass').mockImplementation(SomeClass);
함수에서 반환된 객체 스파이
- 캐시 사용 예시:
// some-path.ts
export function useObject() {
return { method: () => true };
}
// useObject.js
import { useObject } from './some-path.js';
const obj = useObject();
obj.method();
// 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();
모듈의 일부 모킹
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
의 시간도 변경된다는 점에 유의하십시오.
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
를 호출하지 않으면 다른 테스트 간에 자동으로 재설정되지 않습니다.
vi.stubGlobal('__VERSION__', '1.0.0');
expect(__VERSION__).toBe('1.0.0');
import.meta.env
모킹
- 환경 변수 값을 변경하려면 새 값을 할당하면 됩니다.
WARNING
환경 변수 값은 테스트 간에 자동으로 복원되지 않습니다.
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');
});
- 값을 자동으로 재설정하려면
unstubEnvs
설정 옵션을 활성화한 상태에서vi.stubEnv
헬퍼를 사용하거나 (beforeEach
훅에서vi.unstubAllEnvs
를 수동으로 호출) 할 수 있습니다.
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');
});
// vitest.config.ts
export default defineConfig({
test: {
unstubEnvs: true,
},
});