모의 함수 (Mock Functions)
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
의 모든 속성은 초기 상태로 재설정됩니다. 이 메서드는 모의 구현 자체를 재설정하지는 않습니다. 여러 단언 사이에서 모의 상태를 정리하는 데 유용합니다.
각 테스트 실행 전에 이 메서드를 자동으로 호출하려면 구성 파일에서 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) // 첫 번째 호출
.mockImplementationOnce(() => false); // 두 번째 호출
myMockFn(); // 첫 번째 호출: true
myMockFn(); // 두 번째 호출: false
모의 함수에 더 이상 mockImplementationOnce
로 설정된 구현이 없으면, 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 () => { // 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
와 동일하게 호출 기록을 지우고, 추가적으로 내부 구현을 호출 시 undefined
를 반환하는 빈 함수로 재설정합니다. 모든 "once" 구현도 재설정됩니다. 모의를 완전히 초기 상태로 되돌리는 데 유용합니다.
각 테스트 실행 전에 이 메서드를 자동으로 호출하려면 구성 파일에서 mockReset
설정을 활성화하십시오.
mockRestore
function mockRestore(): MockInstance<T>;
mockReset
와 동일하게 호출 기록을 지우고, 추가적으로 내부 구현을 원래 함수로 복원합니다.
vi.fn()
으로 생성된 모의를 복원하면 구현이 undefined
를 반환하는 빈 함수로 설정됩니다. vi.fn(impl)
로 생성된 모의를 복원하면 구현이 impl
로 복원됩니다.
각 테스트 실행 전에 이 메서드를 자동으로 호출하려면 구성 파일에서 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를 사용하는 경우, 원래 함수의 반환 타입과 일치하는 값만 허용됩니다.
모의 함수에 더 이상 mockReturnValueOnce
로 설정된 구현이 없으면, 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';
/**
* The value that was returned from the function.
* If function returned a Promise, then this will be a resolved value.
*/
value: T;
}
interface MockResultIncomplete {
type: 'incomplete';
value: undefined;
}
interface MockResultThrow {
type: 'throw';
/**
* An error that was thrown during function execution.
*/
value: any;
}
type MockResult<T> =
| MockResultReturn<T>
| MockResultThrow
| MockResultIncomplete;
const results: MockResult<ReturnType<T>>[];
이 배열은 모의 함수에서 반환
된 모든 값을 포함합니다. 배열의 각 요소는 type
및 value
속성을 가진 객체입니다. 사용 가능한 타입은 다음과 같습니다.
'return'
- 함수가 오류를 던지지 않고 값을 반환했습니다.'throw'
- 함수 실행 중 오류가 발생했습니다.
value
속성은 반환된 값 또는 던져진 오류를 포함합니다. 함수가 Promise
를 반환한 경우, 약속이 거부되었더라도 result
의 type
은 항상 '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, // 던져진 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>>>[];
이 배열은 비동기 모의 함수에서 해결(fulfilled)
되거나 거부(rejected)
된 모든 값을 포함합니다.
함수가 아직 해결되거나 거부되지 않았다면 이 배열은 비어 있습니다.
const fn = vi.fn().mockResolvedValueOnce('result');
const result = fn();
fn.mock.settledResults === []; // 아직 해결되지 않았으므로 비어 있습니다.
await result; // Promise가 해결될 때까지 기다립니다.
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; // instances에는 생성된 this 컨텍스트가 들어갑니다.
Spy.mock.results[0] === a; // results에는 생성자에서 반환된 값이 들어갑니다.