ts-mockito TypeScript 完整指南:Mock、Stub 与 Spy 实战教程
1. 什么是 ts-mockito?为什么需要它?
ts-mockito 是一个功能强大的 TypeScript 库,用于创建 Mock(模拟对象)、Stub(桩代码)和 Spy(间谍)。它深受 Java 生态中流行的 Mockito 库启发,为从 Java 或 Python 转来的开发者提供了熟悉的 API。ts-mockito 的核心目标是简化单元测试的编写,将被测代码与外部依赖(如数据库、HTTP 客户端、文件系统和其他服务)隔离开来。
为什么需要它?在现代 TypeScript 应用中,类和函数往往依赖于其他组件。如果没有 Mock,测试这些依赖关系就会变成集成测试,需要配置复杂的运行环境。ts-mockito 允许你创建具有预设行为的“假”对象,并验证哪些方法被调用过、调用时传入了哪些参数。这让测试变得快速、确定且易于维护。
该库支持 Mockito 的所有核心功能:通过 mock() 创建 Mock,通过 when() 和 thenReturn() 配置行为,通过 verify() 验证调用,以及通过 spy() 使用 Spy。ts-mockito 完全支持 TypeScript 类型系统,并能与 Jest、Mocha 和 Jasmine 等主流测试框架无缝集成。
2. 安装 ts-mockito
通过 npm(Node 包管理器)安装 ts-mockito。在项目根目录下执行以下命令:
npm install ts-mockito --save-dev
如果你使用 yarn:
yarn add ts-mockito --dev
该库除了 TypeScript 本身(版本 4.0+)之外,没有其他强制依赖。安装完成后,你可以在测试文件中导入所需函数:
import { mock, when, verify, instance, anything, anyOfClass, deepEqual, spy } from 'ts-mockito';
请注意:ts-mockito 使用 Proxy 对象来拦截方法调用。这意味着你始终操作的是“包装过”的对象,而不是类的真实实例。
3. 快速上手——最小可用示例
来看一个最简单的例子:我们有一个 UserService 类,它依赖于 UserRepository。我们希望测试 getUser 方法,而不需要连接真实的数据库。
// user-repository.ts
export class UserRepository {
async findById(id: number): Promise<{ id: number; name: string } | null> {
// 真实的数据库查询
return null;
}
}
// user-service.ts
export class UserService {
constructor(private repository: UserRepository) {}
async getUser(id: number): Promise<string> {
const user = await this.repository.findById(id);
if (!user) {
throw new Error('User not found');
}
return `User: ${user.name}`;
}
}
// user-service.spec.ts
import { mock, when, instance, verify, anything } from 'ts-mockito';
import { UserService } from './user-service';
import { UserRepository } from './user-repository';
describe('UserService', () => {
it('should return user name when user exists', async () => {
// 1. 创建 Repository 的 Mock
const mockRepository: UserRepository = mock(UserRepository);
// 2. 配置行为:当调用 findById(1) 时,返回一个用户对象
when(mockRepository.findById(1)).thenResolve({ id: 1, name: 'Alice' });
// 3. 获取 Mock 的真实实例
const repositoryInstance = i