Nock+TS完全指南:类型安全Mock实战

Nock+TS完全指南:类型安全Mock实战

【免费下载链接】nock 【免费下载链接】nock 项目地址: https://gitcode.com/gh_mirrors/noc/nock

你还在为API Mock类型不匹配抓狂?接口联调时TypeScript报错让测试卡壳?本文将带你用Nock+TS构建类型安全的Mock系统,从类型定义到实战案例,彻底解决前端Mock的类型痛点。读完你将掌握:Nock类型系统核心模块、3种类型安全Mock模式、TypeScript测试最佳实践。

Nock类型系统核心架构

Nock通过types/index.d.ts提供完整类型定义,核心类型构成三层架构:

// 核心类型关系示意
export declare function nock(basePath: string | RegExp | Url | URL, options?: nock.Options): nock.Scope;

declare namespace nock {
  interface Scope extends NodeJS.EventEmitter { /* 拦截器管理 */ }
  interface Interceptor { /* 请求匹配规则 */ }
  type ReplyFnResult = readonly [StatusCode] | readonly [StatusCode, ReplyBody] | readonly [StatusCode, ReplyBody, ReplyHeaders];
}

核心类型解析

Scope接口:作为Mock作用域的入口点,管理一组相关拦截器。通过链式调用定义多个请求匹配规则:

const scope = nock('https://api.example.com')
  .get('/users')
  .reply(200, users)
  .post('/users')
  .reply(201, newUser);

Interceptor接口:定义单个请求的匹配规则和应答策略,支持多种匹配模式:

// 精确匹配
nock('http://example.test').get('/users/1').reply(200)

// 正则匹配
nock('http://example.test').get(/\/users\/\d+/).reply(200)

// 函数匹配
nock('http://example.test').get(uri => uri.startsWith('/users')).reply(200)

ReplyFnResult类型:确保应答格式的类型安全,支持三种返回形式:

  • [statusCode]
  • [statusCode, body]
  • [statusCode, body, headers]

类型安全Mock的三种实现模式

1. 基础类型匹配模式

利用TypeScript类型推断,确保请求参数与应答格式符合预期:

// 正确示例:完整类型定义
interface User {
  id: number;
  name: string;
}

const scope = nock<Scope>('https://api.example.com')
  .get<User>('/users/1')  // 指定返回类型
  .reply(200, { id: 1, name: 'John' });  // 类型检查通过

// 错误示例:类型不匹配
scope.get<User>('/users/1')
  .reply(200, { userId: 1, userName: 'John' });  // TS编译错误:属性不匹配

2. 请求体类型验证模式

通过泛型约束确保请求体结构正确:

interface CreateUserRequest {
  name: string;
  email: string;
}

nock('https://api.example.com')
  .post<CreateUserRequest>('/users', (body) => {
    // 请求体类型自动推断为CreateUserRequest
    return body.email.includes('@');  // 额外业务验证
  })
  .reply(201, (uri, body) => ({
    id: 1,
    ...body  // 类型安全的请求体透传
  }));

3. 高级应答函数模式

使用异步函数处理复杂应答逻辑,同时保持类型安全:

nock('https://api.example.com')
  .get('/data')
  .reply<DataResponse>(async (uri) => {
    const data = await fetchMockData();  // 模拟异步数据获取
    return [200, data];  // 类型检查确保返回[number, DataResponse]
  });

类型测试实战案例

types/tests.ts提供了200+类型测试用例,覆盖各种边界场景:

典型测试用例解析

// 测试查询参数匹配
nock('http://example.test')
  .get('/users')
  .query({ name: 'pedro', surname: 'teixeira' })  // 精确匹配
  .reply(200, { results: [{ id: 'pgte' }] });

// 测试请求头匹配
nock('http://example.test', {
  reqheaders: {
    authorization: 'Basic Auth',
    'X-My-Header': /Awesome/i
  }
})
  .get('/')
  .reply(200);

// 测试延迟应答
nock('http://example.test')
  .get('/')
  .delay(2000)  // 延迟2秒
  .delayBody(1000)  // 响应体延迟1秒
  .reply(200, 'Delayed response');

测试覆盖率分析

Nock的TypeScript类型测试覆盖:

  • ✅ 所有HTTP方法(GET/POST/PUT/DELETE等)
  • ✅ 请求参数/查询/头信息匹配
  • ✅ 应答状态码/体/头信息组合
  • ✅ 异常处理与错误模拟
  • ✅ 延迟与异步场景

最佳实践与避坑指南

类型定义扩展技巧

自定义类型扩展满足特定业务需求:

// 扩展Nock类型定义
declare module 'nock' {
  interface Scope {
    // 添加自定义方法
    log(message: string): this;
  }
}

// 使用扩展方法
nock('https://api.example.com')
  .log(console.log)  // 自定义日志方法
  .get('/')
  .reply(200);

常见类型问题解决方案

  1. 问题:复杂嵌套对象类型不匹配 方案:使用类型断言与类型守卫结合
// 类型守卫函数
function isUserResponse(data: unknown): data is UserResponse {
  return typeof data === 'object' && data !== null && 'id' in data;
}

nock('https://api.example.com')
  .get('/user')
  .reply(200, (uri, body) => {
    const response = fetchData();
    if (!isUserResponse(response)) {
      throw new Error('Invalid response type');
    }
    return response;
  });
  1. 问题:第三方库类型冲突 方案:使用module augmentation隔离类型
// 隔离第三方类型冲突
declare module 'nock' {
  namespace Nock {
    interface Options {
      // 扩展自定义选项
      myCustomOption?: boolean;
    }
  }
}

总结与进阶方向

Nock的TypeScript类型系统通过types/index.d.ts实现了完整的类型覆盖,结合本文介绍的三种模式,可构建从简单到复杂的类型安全Mock系统。建议进一步学习:

掌握Nock+TS的类型安全Mock技术,让你的API测试从"运行时发现错误"升级为"编译时预防错误",大幅提升前端工程质量与开发效率。

点赞+收藏本文,关注作者获取更多TypeScript工程化实践指南!下期预告:《Nock与React组件测试深度整合》

【免费下载链接】nock 【免费下载链接】nock 项目地址: https://gitcode.com/gh_mirrors/noc/nock

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值