SinonJS 实战:TypeScript与SWC环境下的依赖项替换方案

SinonJS 实战:TypeScript与SWC环境下的依赖项替换方案

sinon Test spies, stubs and mocks for JavaScript. sinon 项目地址: https://gitcode.com/gh_mirrors/si/sinon

引言

在现代前端测试领域,SinonJS作为创建测试替身(测试工具、模拟函数、存根)的利器广受欢迎。然而在TypeScript和SWC等现代工具链的组合下,依赖项替换往往会遇到意想不到的挑战。本文将深入剖析一个典型场景,并提供多种解决方案。

问题场景

技术栈组合

  • 测试框架:Mocha
  • 转译工具:SWC(基于Rust的高性能转译器)
  • 开发语言:TypeScript
  • 测试工具:SinonJS
  • 模块系统:CommonJS

核心问题

当尝试使用Sinon替换other.ts模块中的toBeMocked函数时,SWC转译后的代码会抛出错误:

TypeError: Descriptor for property toBeMocked is non-configurable and non-writable

根本原因分析

通过Object.getOwnPropertyDescriptors对比两种转译结果:

SWC输出

{
  toBeMocked: {
    get: [Function: get],
    configurable: false  // 关键问题所在
  }
}

ts-node输出

{
  toBeMocked: {
    value: [Function],
    writable: true,
    configurable: true  // 可配置
  }
}

SWC将模块导出转换为不可配置的getter访问器,导致Sinon无法修改属性。

解决方案集

方案一:修改SWC转译输出

适用场景:希望保持原有测试写法不变的情况

  1. 安装SWC插件:
npm install swc_mut_cjs_exports
  1. 修改.swcrc配置:
{
  "jsc": {
    "experimental": {
      "plugins": [["swc_mut_cjs_exports", {}]]
    }
  }
}
  1. 调整测试代码:
// 使用replaceGetter替代常规stub
const stub = sandbox.fake.returns("mocked");
sandbox.replaceGetter(Other, "toBeMocked", () => stub);

优点:保持原有代码结构 缺点:依赖特定SWC插件

方案二:依赖注入模式

基础版(手动管理)
// other.ts
export let toBeMocked = () => "原始实现";

// 测试文件
beforeEach(() => {
  original = Other.toBeMocked;
  Other.toBeMocked = sinon.stub().returns("模拟值");
});

afterEach(() => {
  Other.toBeMocked = original;
});
增强版(自动清理)
// other.ts
export const mockable = {
  get toBeMocked() { return originalImpl },
  set toBeMocked(fn) { /*...*/ }
};

// 测试文件
sandbox.replace.usingAccessor(Other.mockable, 'toBeMocked', stub);

优点:不依赖转译工具 缺点:需要修改生产代码

方案三:模块加载劫持

使用quibble等工具拦截require调用:

before(() => {
  quibble("./other", { 
    toBeMocked: sinon.stub().returns("模拟值") 
  });
  main = require("./main").main;
});

优点:无需修改生产代码 缺点:需要了解模块系统原理

方案对比

| 方案 | 侵入性 | 复杂度 | 适用场景 | |------|--------|--------|----------| | SWC插件 | 低 | 中 | 长期使用SWC的项目 | | 依赖注入 | 中 | 低 | 需要明确依赖关系的项目 | | 模块劫持 | 高 | 高 | 遗留系统改造 |

最佳实践建议

  1. 新项目:优先考虑依赖注入模式,虽然需要额外代码,但测试意图更明确
  2. 现有项目:根据构建工具选择:
    • 使用SWC:考虑插件方案
    • 使用webpack:可探索loader方案
  3. 混合环境:结合Sinon的sandbox机制,确保测试隔离性

调试技巧

当遇到类似问题时,推荐使用以下诊断方法:

console.log(Object.getOwnPropertyDescriptors(importedModule));

这个方法可以快速揭示模块导出的实际属性描述符,是解决模块替换问题的第一把钥匙。

结语

在复杂的现代前端工具链中,测试替身的管理确实充满挑战。通过本文介绍的多种方案,开发者可以根据项目实际情况选择最适合的解决路径。记住,没有放之四海而皆准的完美方案,只有最适合当前上下文的选择。

sinon Test spies, stubs and mocks for JavaScript. sinon 项目地址: https://gitcode.com/gh_mirrors/si/sinon

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

昌隽艳

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

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

抵扣说明:

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

余额充值