如何在 JavaScript 中覆盖全局函数以实现单元测试模拟

10次阅读

如何在 JavaScript 中覆盖全局函数以实现单元测试模拟

本文介绍通过函数表达式替代函数声明的方式,在不修改原始逻辑的前提下,安全地覆盖全局函数以支持单元测试中的行为模拟。

javaScript 单元测试中,常需对依赖的底层函数(如 getData)进行模拟(mock),以隔离被测函数(如 getUsers)的行为。但若目标函数是使用函数声明function getData() { … })定义的,因其存在提升(hoisting) 且绑定在作用域顶层,直接赋值覆盖(如 getData = mock_getData)在严格模式下可能无效,或因执行时机问题导致未生效。

✅ 正确做法是:统一使用函数表达式定义可模拟的全局函数。这样它们就成为可重赋值的变量,便于在测试前动态替换:

// ✅ 推荐:用函数表达式定义,而非函数声明 var getData = function() {   // 实际逻辑:从数据库获取数据   throw new Error('Real database call — should not run in tests'); };  var getUsers = function() {   var data = getData(); // 调用的是当前绑定的 getData   return data.map(user => ({ ...user, loaded: true })); };  function main() {   var users = getUsers();   // ... }

随后,在测试入口处(如 runTests 前),通过简单赋值即可完成模拟:

// ? 测试前:覆盖 getData 为模拟实现 var getData = function() {   return [{ id: 0, name: 'Alice' }, { id: 1, name: 'Bob' }]; };  test('getUsers', function() {   var users = getUsers(); // 现在调用的是模拟版 getData   myAssert(users.length, 2);   myAssert(users[0].name, 'Alice');   myAssert(users[1].name, 'Bob'); });

? 关键优势

立即学习Java免费学习笔记(深入)”;

  • 无需引入外部测试框架(如 Jest 的 jest.mock);
  • 零侵入原始业务代码(仅需将 function xxx() {…} 改为 var xxx = function() {…});
  • 模拟与真实实现共用同一标识符,语义清晰、维护成本低;
  • 支持按需开关(例如结合 _DEBUG = true 统一控制)。

⚠️ 注意事项:

  • 所有被模拟的函数必须定义为可变变量(var / let),不可用 const
  • 模拟赋值必须在被测函数首次调用之前执行(推荐放在 runTests() 开头);
  • 若模块化环境(ESM)中,全局变量不可写,此时应改用依赖注入或代理模式;
  • 生产构建时建议通过打包工具(如 webpack DefinePlugin)自动移除模拟逻辑,避免泄露。

总结:函数表达式 + 可变变量绑定,是最轻量、最可控的原生 javascript 函数模拟方案,特别适合微型测试库或教学/原型场景。

text=ZqhQzanResources