> For AI agents: the complete documentation index is available at /zh/llms.txt, the full documentation bundle is available at /zh/llms-full.txt.

# Mock functions

Rstest 基于 [tinyspy](https://github.com/tinylibs/tinyspy) 提供了一些工具方法帮助你进行函数的模拟（mock）。

## rs.fn

- **别名：** `rstest.fn`
- **类型：**

```ts
type FunctionLike = (...args: any) => any;

export interface Mock<
  T extends FunctionLike = FunctionLike,
> extends MockInstance<T> {
  new (...args: Parameters<T>): ReturnType<T>;
  (...args: Parameters<T>): ReturnType<T>;
}

export type MockFn = <T extends FunctionLike = FunctionLike>(fn?: T) => Mock<T>;
```

创建一个 mock 函数。

如果需要为可调用的 mock 函数标注类型，请参考 [`Mock`](/zh/api/javascript-api/types.md#mock) 类型。

```ts
const sayHi = rs.fn((name: string) => `hi ${name}`);

const res = sayHi('bob');

expect(res).toBe('hi bob');

expect(sayHi).toHaveBeenCalledTimes(1);
```

## rs.spyOn

- **别名：** `rstest.spyOn`
- **类型：**

```ts
export type SpyFn = <T extends Record<string, any>, K extends keyof T>(
  obj: T,
  methodName: K,
  accessType?: 'get' | 'set',
) => MockInstance<T[K]>;
```

对一个对象的方法进行 mock。

关于 spy 返回的控制 API，请参考 [`MockInstance`](/zh/api/javascript-api/types.md#mockinstance) 类型。

```ts
const sayHi = () => 'hi';
const hi = {
  sayHi,
};

const spy = rs.spyOn(hi, 'sayHi');

expect(hi.sayHi()).toBe('hi');

expect(spy).toHaveBeenCalled();
```

对同一个方法重复调用 `rs.spyOn` 时，会返回已有的 spy，而不是重新定义。

```ts
const hi = {
  sayHi: () => 'hi',
};
rs.spyOn(hi, 'sayHi').mockImplementation(() => 'hello');

expect(hi.sayHi()).toBe('hello');

// 返回的 spy 实例与第一次调用相同
expect(rs.spyOn(hi, 'sayHi')).toBeCalled();
```

:::note 对 re-export 或第三方模块的导出进行 spy

`rs.spyOn` 能作用于你所导入模块中**直接定义**的导出，但对从其他模块 **re-export**（`export * from '...'`）或由第三方依赖提供的导出可能不生效。

这种情况下，请改用 [`{ spy: true }`](/zh/api/runtime-api/rstest/mock-modules.md#with-spy-true-option) 来 mock 该模块。它会在保留真实实现的同时，为每个导出装上 spy：

```ts
rs.mock('pkg', { spy: true });
```

:::

## rs.isMockFunction

- **别名：** `rstest.isMockFunction`
- **类型：** `(fn: any) => fn is MockInstance`

判断给定的函数是否为 mock 函数。

## rs.mockObject

- **别名：** `rstest.mockObject`
- **类型：**

```ts
type MockObject = <T>(
  object: T,
  options?: { spy?: boolean },
) => MaybeMockedDeep<T>;
```

创建一个对象的深度 mock。所有方法都会被替换为 mock 函数，而原始值和普通对象会保留。

### 基本用法

```ts
const original = {
  method() {
    return 42;
  },
  nested: {
    getValue() {
      return 'real';
    },
  },
  prop: 'foo',
};

const mocked = rs.mockObject(original);

// 方法默认返回 undefined
expect(mocked.method()).toBe(undefined);
expect(mocked.nested.getValue()).toBe(undefined);

// 原始值保持不变
expect(mocked.prop).toBe('foo');

// 方法是 mock 函数
expect(rs.isMockFunction(mocked.method)).toBe(true);
```

### Mock 返回值

你可以配置 mock 方法返回特定的值：

```ts
const mocked = rs.mockObject({
  fetchData: () => 'real data',
});

mocked.fetchData.mockReturnValue('mocked data');

expect(mocked.fetchData()).toBe('mocked data');
```

### Spy 模式

当传入 `{ spy: true }` 作为第二个参数时，原始实现会被保留，同时仍然追踪调用：

```ts
const original = {
  add: (a: number, b: number) => a + b,
};

const spied = rs.mockObject(original, { spy: true });

// 保留原始实现
expect(spied.add(1, 2)).toBe(3);

// 追踪调用
expect(spied.add).toHaveBeenCalledWith(1, 2);
expect(spied.add.mock.results[0]).toEqual({ type: 'return', value: 3 });
```

### 数组

默认情况下，数组会被替换为空数组。使用 `{ spy: true }` 时，数组保持其原始值：

```ts
const mocked = rs.mockObject({ array: [1, 2, 3] });
expect(mocked.array).toEqual([]);

const spied = rs.mockObject({ array: [1, 2, 3] }, { spy: true });
expect(spied.array).toEqual([1, 2, 3]);
```

### Mock 类

你也可以 mock 类构造函数。使用 `{ spy: true }` 可以保留原始类的行为，同时追踪调用：

```ts
class UserService {
  getUser() {
    return { id: 1, name: 'Alice' };
  }
}

// 使用 { spy: true } 保留原始实现
const MockedService = rs.mockObject(UserService, { spy: true });
const instance = new MockedService();

// 原始方法正常工作
expect(instance.getUser()).toEqual({ id: 1, name: 'Alice' });

// 覆盖实现
rs.mocked(instance.getUser).mockImplementation(() => ({ id: 2, name: 'Bob' }));
expect(instance.getUser()).toEqual({ id: 2, name: 'Bob' });
```

## rs.mocked

- **别名：** `rstest.mocked`
- **类型：**

```ts
type MockedFn = <T>(
  item: T,
  deepOrOptions?: boolean | { partial?: boolean; deep?: boolean },
) =>
  | Mocked<T>
  | MaybeMockedDeep<T>
  | MaybePartiallyMocked<T>
  | MaybePartiallyMockedDeep<T>;
```

一个 TypeScript 类型辅助函数，用于将对象包装为 mock 类型而不改变其运行时行为。当你 mock 了一个模块并想要获得正确的 mock 方法类型提示时，这很有用。

推导出的返回类型会随选项变化：`{ deep: true }` 会递归应用 mock 类型，`{ partial: true }` 则使用 partial mock 类型。

如果需要为 mock 对象或模块标注类型，请参考 [`Mocked`](/zh/api/javascript-api/types.md#mocked) 类型。

```ts
import { myModule } from './myModule';

rs.mock('./myModule', { spy: true });

// TypeScript 现在知道 myModule.method 是一个 MockInstance
const mockedModule = rs.mocked(myModule);

mockedModule.method.mockReturnValue('mocked');
```

该函数在运行时只是返回相同的对象——它只影响 TypeScript 类型。

## rs.clearAllMocks

- **别名：** `rstest.clearAllMocks`
- **类型：** `() => RstestUtilities`

清除所有 mock 的 `mock.calls`、`mock.instances`、`mock.contexts` 和 `mock.results` 属性。

## rs.resetAllMocks

- **别名：** `rstest.resetAllMocks`
- **类型：** `() => RstestUtilities`

清除所有 mock 属性，并将每个 mock 的实现重置为其原始实现。

## rs.restoreAllMocks

- **别名：** `rstest.restoreAllMocks`
- **类型：** `() => RstestUtilities`

重置所有 mock，并恢复被 mock 的对象的原始描述符。

## 更多

- [Mock 匹配器](/zh/api/runtime-api/test-api/expect.md#mock-匹配器)
- [MockInstance API](/zh/api/runtime-api/rstest/mock-instance.md)
