Mock 함수
vi.fn
메서드를 사용하여 모의 함수를 생성하고 해당 실행을 추적할 수 있습니다. 이미 생성된 객체의 메서드를 추적하려면 vi.spyOn
메서드를 사용할 수 있습니다.
import { vi } from 'vitest';
const fn = vi.fn();
fn('hello world');
fn.mock.calls[0] === ['hello world'];
const market = {
getApples: () => 100,
};
const getApplesSpy = vi.spyOn(market, 'getApples');
market.getApples();
getApplesSpy.mock.calls.length === 1;
모의 결과를 검증하려면 expect
에서 toHaveBeenCalled
와 같은 모의 단언을 사용해야 합니다. 이 API 참조는 모의 동작을 조작하는 데 사용할 수 있는 속성 및 메서드를 설명합니다.
TIP
아래 타입 정의에서 사용자 정의 함수 구현은 제네릭 <T>
로 표시됩니다.
getMockImplementation
function getMockImplementation(): T | undefined;
현재 모의 구현이 있다면 반환합니다.
모의가 vi.fn
으로 생성된 경우, 제공된 메서드를 모의 구현으로 사용합니다.
모의가 vi.spyOn
으로 생성된 경우, 사용자 정의 구현이 제공되지 않으면 undefined
를 반환합니다.
getMockName
function getMockName(): string;
.mockName(name)
메서드로 모의에 할당된 이름을 반환하는 데 사용합니다. 기본적으로 vi.fn()
을 반환합니다.
mockClear
function mockClear(): MockInstance<T>;
모든 호출 기록을 지웁니다. 호출 후 .mock
의 모든 속성은 초기 상태로 돌아갑니다. 이 메서드는 구현을 재설정하지 않습니다. 이는 서로 다른 단언 사이에서 모의를 정리하는 데 유용합니다.
const person = {
greet: (name: string) => `Hello ${name}`,
};
const spy = vi.spyOn(person, 'greet').mockImplementation(() => 'mocked');
expect(person.greet('Alice')).toBe('mocked');
expect(spy.mock.calls).toEqual([['Alice']]);
// 호출 기록을 지우지만 모의 구현은 유지합니다.
spy.mockClear();
expect(spy.mock.calls).toEqual([]);
expect(person.greet('Bob')).toBe('mocked');
expect(spy.mock.calls).toEqual([['Bob']]);
각 테스트 전에 이 메서드를 자동으로 호출하려면 구성에서 clearMocks
설정을 활성화하십시오.
mockName
function mockName(name: string): MockInstance<T>;
내부 모의 이름을 설정합니다. 이는 단언이 실패할 때 모의를 식별하는 데 유용합니다.
mockImplementation
function mockImplementation(fn: T): MockInstance<T>;
모의 구현으로 사용될 함수를 받습니다. TypeScript는 인자와 반환 타입이 원본 함수의 것과 일치할 것을 예상합니다.
const mockFn = vi.fn().mockImplementation((apples: number) => apples + 1);
// 또는: vi.fn(apples => apples + 1);
const NelliesBucket = mockFn(0);
const BobsBucket = mockFn(1);
NelliesBucket === 1; // true
BobsBucket === 2; // true
mockFn.mock.calls[0][0] === 0; // true
mockFn.mock.calls[1][0] === 1; // true
mockImplementationOnce
function mockImplementationOnce(fn: T): MockInstance<T>;
모의 구현으로 사용될 함수를 받습니다. TypeScript는 인자와 반환 타입이 원본 함수의 것과 일치할 것을 예상합니다. 이 메서드는 여러 함수 호출에 대해 다른 결과를 생성하도록 연속적으로 체이닝될 수 있습니다.
const myMockFn = vi
.fn()
.mockImplementationOnce(() => true) // 1번째 호출
.mockImplementationOnce(() => false); // 2번째 호출
myMockFn(); // 1번째 호출: true
myMockFn(); // 2번째 호출: false
모의 함수에 더 이상 구현이 없으면, vi.fn(() => defaultValue)
또는 .mockImplementation(() => defaultValue)
가 호출된 경우 설정된 기본 구현을 호출합니다.
const myMockFn = vi
.fn(() => 'default')
.mockImplementationOnce(() => 'first call')
.mockImplementationOnce(() => 'second call');
// 'first call', 'second call', 'default', 'default'
console.log(myMockFn(), myMockFn(), myMockFn(), myMockFn());
withImplementation
function withImplementation(fn: T, cb: () => void): MockInstance<T>;
function withImplementation(
fn: T,
cb: () => Promise<void>
): Promise<MockInstance<T>>;
콜백이 실행되는 동안 원본 모의 구현을 일시적으로 재정의합니다.
const myMockFn = vi.fn(() => 'original');
myMockFn.withImplementation(
() => 'temp',
() => {
myMockFn(); // 'temp'
}
);
myMockFn(); // 'original'
비동기 콜백과 함께 사용할 수 있습니다. 원본 구현을 나중에 사용하려면 메서드를 await
해야 합니다.
test('async callback', async () => {
const myMockFn = vi.fn(() => 'original');
// 콜백이 비동기이므로 이 호출을 await합니다.
await myMockFn.withImplementation(
() => 'temp',
async () => {
myMockFn(); // 'temp'
}
);
myMockFn(); // 'original'
});
이 메서드는 mockImplementationOnce
보다 우선순위가 높습니다.
mockRejectedValue
function mockRejectedValue(value: unknown): MockInstance<T>;
비동기 함수가 호출될 때 거부될 오류를 받습니다.
const asyncMock = vi.fn().mockRejectedValue(new Error('Async error'));
await asyncMock(); // Error('Async error')를 던집니다.
mockRejectedValueOnce
function mockRejectedValueOnce(value: unknown): MockInstance<T>;
다음 함수 호출 시 거부될 값을 받습니다. 체인으로 연결된 경우, 각 연속 호출은 지정된 값을 거부합니다.
const asyncMock = vi
.fn()
.mockResolvedValueOnce('first call')
.mockRejectedValueOnce(new Error('Async error'));
await asyncMock(); // 'first call'
await asyncMock(); // Error('Async error')를 던집니다.
mockReset
function mockReset(): MockInstance<T>;
mockClear
가 하는 일을 수행하고 내부 구현을 원본 함수로 재설정합니다. 이것은 또한 모든 "once" 구현을 재설정합니다.
vi.fn()
으로 생성된 모의를 재설정하면 구현이 undefined
를 반환하는 빈 함수로 설정됩니다. vi.fn(impl)
에서 모의를 재설정하면 구현이 impl
로 복원됩니다.
이는 모의를 원래 상태로 재설정하려는 경우에 유용합니다.
const person = {
greet: (name: string) => `Hello ${name}`,
};
const spy = vi.spyOn(person, 'greet').mockImplementation(() => 'mocked');
expect(person.greet('Alice')).toBe('mocked');
expect(spy.mock.calls).toEqual([['Alice']]);
// 호출 기록을 지우고 구현을 재설정하지만, 메서드는 여전히 스파이됩니다.
spy.mockReset();
expect(spy.mock.calls).toEqual([]);
expect(person.greet).toBe(spy);
expect(person.greet('Bob')).toBe('Hello Bob');
expect(spy.mock.calls).toEqual([['Bob']]);
각 테스트 전에 이 메서드를 자동으로 호출하려면 구성에서 mockReset
설정을 활성화하십시오.
mockRestore
function mockRestore(): MockInstance<T>;
mockReset
이 하는 일을 수행하고 스파이된 객체의 원본 디스크립터를 복원합니다.
vi.fn()
에서 모의를 복원하면 구현이 undefined
를 반환하는 빈 함수로 설정됩니다. vi.fn(impl)
에서 모의를 복원하면 구현이 impl
로 복원됩니다.
const person = {
greet: (name: string) => `Hello ${name}`,
};
const spy = vi.spyOn(person, 'greet').mockImplementation(() => 'mocked');
expect(person.greet('Alice')).toBe('mocked');
expect(spy.mock.calls).toEqual([['Alice']]);
// 호출 기록을 지우고 스파이된 객체 메서드를 복원합니다.
spy.mockRestore();
expect(spy.mock.calls).toEqual([]);
expect(person.greet).not.toBe(spy);
expect(person.greet('Bob')).toBe('Hello Bob');
expect(spy.mock.calls).toEqual([]);
각 테스트 전에 이 메서드를 자동으로 호출하려면 구성에서 restoreMocks
설정을 활성화하십시오.
mockResolvedValue
function mockResolvedValue(value: Awaited<ReturnType<T>>): MockInstance<T>;
비동기 함수가 호출될 때 해결될 값을 받습니다. TypeScript는 원본 함수의 반환 타입과 일치하는 값만 허용합니다.
const asyncMock = vi.fn().mockResolvedValue(42);
await asyncMock(); // 42
mockResolvedValueOnce
function mockResolvedValueOnce(value: Awaited<ReturnType<T>>): MockInstance<T>;
다음 함수 호출 시 해결될 값을 받습니다. TypeScript는 원본 함수의 반환 타입과 일치하는 값만 허용합니다. 체인으로 연결된 경우, 각 연속 호출은 지정된 값을 해결합니다.
const asyncMock = vi
.fn()
.mockResolvedValue('default')
.mockResolvedValueOnce('first call')
.mockResolvedValueOnce('second call');
await asyncMock(); // first call
await asyncMock(); // second call
await asyncMock(); // default
await asyncMock(); // default
mockReturnThis
function mockReturnThis(): MockInstance<T>;
실제 구현을 호출하지 않고 메서드에서 this
컨텍스트를 반환해야 하는 경우에 사용합니다. 이는 다음의 약어입니다.
spy.mockImplementation(function () {
return this;
});
mockReturnValue
function mockReturnValue(value: ReturnType<T>): MockInstance<T>;
모의 함수가 호출될 때마다 반환될 값을 받습니다. TypeScript는 원본 함수의 반환 타입과 일치하는 값만 허용합니다.
const mock = vi.fn();
mock.mockReturnValue(42);
mock(); // 42
mock.mockReturnValue(43);
mock(); // 43
mockReturnValueOnce
function mockReturnValueOnce(value: ReturnType<T>): MockInstance<T>;
모의 함수가 호출될 때마다 반환될 값을 받습니다. TypeScript는 원본 함수의 반환 타입과 일치하는 값만 허용합니다.
모의 함수에 더 이상 구현이 없으면, vi.fn(() => defaultValue)
또는 .mockImplementation(() => defaultValue)
가 호출된 경우 설정된 기본 구현을 호출합니다.
const myMockFn = vi
.fn()
.mockReturnValue('default')
.mockReturnValueOnce('first call')
.mockReturnValueOnce('second call');
// 'first call', 'second call', 'default', 'default'
console.log(myMockFn(), myMockFn(), myMockFn(), myMockFn());
mock.calls
const calls: Parameters<T>[];
이 배열은 각 호출 시 사용된 모든 인수를 포함합니다. 배열의 한 항목은 해당 호출의 인수입니다.
const fn = vi.fn();
fn('arg1', 'arg2');
fn('arg3');
fn.mock.calls ===
[
['arg1', 'arg2'], // 첫 번째 호출
['arg3'], // 두 번째 호출
];
mock.lastCall
const lastCall: Parameters<T> | undefined;
이것은 마지막 호출의 인수를 포함합니다. 모의 함수가 한 번도 호출되지 않았다면 undefined
를 반환합니다.
mock.results
interface MockResultReturn<T> {
type: 'return';
/**
* 함수에서 반환된 값입니다.
* 함수가 Promise를 반환했다면, 이것은 해결된 값이 됩니다.
*/
value: T;
}
interface MockResultIncomplete {
type: 'incomplete';
value: undefined;
}
interface MockResultThrow {
type: 'throw';
/**
* 함수 실행 중 발생한 오류입니다.
*/
value: any;
}
type MockResult<T> =
| MockResultReturn<T>
| MockResultThrow
| MockResultIncomplete;
const results: MockResult<ReturnType<T>>[];
이것은 함수에서 반환된
모든 값을 포함하는 배열입니다. 배열의 한 항목은 type
및 value
속성을 가진 객체입니다. 사용 가능한 타입은 다음과 같습니다.
'return'
- 함수가 예외를 발생시키지 않고 정상적으로 반환되었습니다.'throw'
- 함수가 예외를 발생시켰습니다.
value
속성은 반환된 값 또는 던져진 오류를 포함합니다. 함수가 Promise
를 반환했다면, 프라미스가 거부되었더라도 result
는 항상 'return'
이 됩니다.
const fn = vi
.fn()
.mockReturnValueOnce('result')
.mockImplementationOnce(() => {
throw new Error('thrown error');
});
const result = fn(); // 'result' 반환
try {
fn(); // Error 던짐
} catch {}
fn.mock.results ===
[
// 첫 번째 결과
{
type: 'return',
value: 'result',
},
// 마지막 결과
{
type: 'throw',
value: Error,
},
];
mock.settledResults
interface MockSettledResultFulfilled<T> {
type: 'fulfilled';
value: T;
}
interface MockSettledResultRejected {
type: 'rejected';
value: any;
}
export type MockSettledResult<T> =
| MockSettledResultFulfilled<T>
| MockSettledResultRejected;
const settledResults: MockSettledResult<Awaited<ReturnType<T>>>[];
함수에서 해결
되거나 거부
된 모든 값을 포함하는 배열입니다.
함수가 해결되거나 거부된 적이 없다면 이 배열은 비어 있습니다.
const fn = vi.fn().mockResolvedValueOnce('result');
const result = fn();
fn.mock.settledResults === [];
await result;
fn.mock.settledResults ===
[
{
type: 'fulfilled',
value: 'result',
},
];
mock.invocationCallOrder
const invocationCallOrder: number[];
이 속성은 모의 함수의 실행 순서를 반환합니다. 모든 정의된 모의 간에 공유되는 숫자 배열입니다.
const fn1 = vi.fn();
const fn2 = vi.fn();
fn1();
fn2();
fn1();
fn1.mock.invocationCallOrder === [1, 3];
fn2.mock.invocationCallOrder === [2];
mock.contexts
const contexts: ThisParameterType<T>[];
이 속성은 모의 함수에 대한 각 호출 중에 사용된 this
값의 배열입니다.
const fn = vi.fn();
const context = {};
fn.apply(context);
fn.call(context);
fn.mock.contexts[0] === context;
fn.mock.contexts[1] === context;
mock.instances
const instances: ReturnType<T>[];
이 속성은 모의 함수가 new
키워드와 함께 호출될 때 생성된 모든 인스턴스를 포함하는 배열입니다. 이것은 함수의 실제 컨텍스트(this
)이며, 반환 값과는 다름을 유의하십시오.
WARNING
모의가 new MyClass()
로 인스턴스화된 경우, mock.instances
는 하나의 값만 포함하는 배열이 됩니다.
const MyClass = vi.fn();
const a = new MyClass();
MyClass.mock.instances[0] === a;
생성자에서 값을 반환하면 instances
배열이 아닌 results
내부에 포함됩니다.
const Spy = vi.fn(() => ({ method: vi.fn() }));
const a = new Spy();
Spy.mock.instances[0] !== a;
Spy.mock.results[0] === a;