nock TypeScript 教程:HTTP 模拟测试完整指南

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

nock TypeScript 教程:HTTP 模拟测试实战指南

1. 什么是 nock?为什么需要它?

nock 是一个强大的 Node.js 库,专门用于拦截和模拟 HTTP 请求。它允许开发者模拟外部服务(如 REST API、第三方微服务、Webhook)的响应,而无需实际发起网络请求。这在编写单元测试和集成测试时尤为重要,因为测试的稳定性和执行速度至关重要。

为什么需要它?假设你的应用需要向支付网关、天气 API 或通过 HTTP 访问数据库发送请求。在测试环境中,你不想依赖这些服务的可用性、响应速度或请求限制。nock 可以“替换”这些请求,返回预设的数据。这让测试变得快速、可预测且与外部因素隔离。此外,你还可以测试错误场景(超时、500 错误、空响应),这些在真实环境中很难复现。

在 TypeScript 环境中,nock 与流行的测试框架(Jest、Mocha、Vitest)完美集成,并支持类型定义,使开发更便捷、更安全。该库在 Node.js 层面(通过 http 和 https 模块)拦截请求,因此适用于任何 HTTP 客户端:axios、node-fetch、got,甚至原生的 fetch(需注意一些细节)。

2. 安装指南

要在 TypeScript 项目中安装 nock,请在终端中执行以下任一命令:

# 使用 npm
npm install --save-dev nock @types/nock

# 使用 yarn
yarn add --dev nock @types/nock

# 使用 pnpm
pnpm add --save-dev nock @types/nock

注意: @types/nock 包含 TypeScript 的类型声明。如果你使用 TypeScript 4.0 或更高版本,类型可能已内置在库中,但为了兼容性,建议显式安装。

3. 快速上手

让我们编写一个最小测试示例,展示 nock 的基本用法。假设我们有一个从外部 API 获取用户数据的函数。

// userService.ts
import axios from 'axios';

export async function getUser(userId: number): Promise<{ id: number; name: string; email: string }> {
    const response = await axios.get(`https://jsonplaceholder.typicode.com/users/${userId}`);
    return response.data;
}

现在编写一个测试,模拟这个请求:

// userService.test.ts
import nock from 'nock';
import { getUser } from './userService';

describe('getUser', () => {
    afterEach(() => {
        nock.cleanAll(); // 每个测试后清除所有模拟
    });

    it('应该返回用户数据', async () => {
        // 1. 配置拦截
        const mockUser = { id: 1, name: '张三', email: 'zhangsan@example.com' };
        nock('https://jsonplaceholder.typicode.com')
            .get('/users/1')
            .reply(200, mockUser);

        // 2. 调用被测试函数
        const user = await getUser(1);

        // 3. 验证结果
        expect(user).toEqual(mockUser);
    });

    it('应该在 500 错误时抛出异常', async () => {
        nock('https://jsonplaceholder.typicode.com')
            .get('/users/1')
            .reply(500, { error: '服务器错误' });

        await expect(getUser(1)).rejects.toThrow();
    });
});

这个示例展示了如何轻松模拟服务器响应,并测试成功和错误两种场景。

4. 核心方法详解

nock 提供了丰富的方法来精确控制 HTTP 请求的模拟。以下是最常用的方法:

  • nock(baseUrl):创建一个拦截器,匹配指定基础 URL 的请求。
  • .get(path)、.post(path)、.put(path)、.delete(path):指定要拦截的 HTTP 方法和路径。
  • .reply(statusCode, body, headers?):设置模拟响应的状态码、响应体和可选的头信息。
  • .query(queryObject):匹配特定的查询参数。
  • .times(n):限制拦截器被使用的次数。
  • .persist():使拦截器持久化,可被多次使用。
  • .delay(duration):模拟网络延迟。

例如,模拟一个带查询参数的 POST 请求:

nock('https://api.example.com')
    .post('/data', { key: 'value' })
    .query({ page: 1 })
    .reply(201, { id: 123 });

5. 高级用法与最佳实践

在实际项目中,nock 可以处理更复杂的场景:

  • 匹配请求体:使用 .post(path, body) 精确匹配请求体内容。
  • 动态响应:使用回调函数根据请求动态生成响应。
  • 记录和重放:结合 nock.recorder 记录真实请求,然后在测试中重放。
  • 清理和重置:使用 nock.cleanAll() 和 nock.restore() 确保测试隔离。

最佳实践:

  • 在每个测试后调用 nock.cleanAll(),避免测试间相互影响。
  • 使用 nock.isDone() 验证所有预期的拦截器是否都被调用。
  • 对于集成测试,考虑使用 nock.back 模式,将真实请求记录为 fixture 文件。

推荐