如何用Sinon对instanceof进行Spy?测试验证遇阻求助
如何用Sinon监视
instanceof的调用 直接监视instanceof运算符本身是行不通的,因为它是JavaScript的原生运算符,不是可被Spy的函数。不过我们可以利用ES6引入的Symbol.hasInstance特性,或者通过封装函数的方式来间接实现检测。下面是两种可行的方案:
方案1:利用Symbol.hasInstance(ES6+)
从ES6开始,instanceof的行为会调用目标构造函数的Symbol.hasInstance方法(默认实现就是检查原型链)。我们可以对这个方法进行Spy,从而检测instanceof是否被调用。
示例代码:
const sinon = require('sinon'); // 假设我们要监视的构造函数是MyClass const MyClass = function() {}; // 1. 保存原始的hasInstance方法 const originalHasInstance = MyClass[Symbol.hasInstance]; // 2. 创建Spy并替换原方法 const hasInstanceSpy = sinon.spy(function(obj) { // 调用原始逻辑保证功能正常 return originalHasInstance.call(this, obj); }); MyClass[Symbol.hasInstance] = hasInstanceSpy; // 3. 执行你的被测代码(比如某个会用到obj instanceof MyClass的函数) function underTest(obj) { return obj instanceof MyClass; } underTest(new MyClass()); // 4. 断言Spy被调用 sinon.assert.calledOnce(hasInstanceSpy); // 还可以断言调用参数 sinon.assert.calledWith(hasInstanceSpy, sinon.match.instanceOf(MyClass)); // 5. 恢复原始方法,避免影响其他测试 MyClass[Symbol.hasInstance] = originalHasInstance;
如果你的环境支持sinon.stub的wrap方法,还可以更简洁地实现:
const hasInstanceStub = sinon.stub(MyClass, Symbol.hasInstance).callsFake(function(obj) { return MyClass[Symbol.hasInstance].wrappedMethod.call(this, obj); }); // 执行测试... sinon.assert.called(hasInstanceStub); hasInstanceStub.restore();
方案2:封装instanceof调用(兼容旧环境)
如果你的运行环境不支持ES6的Symbol.hasInstance,或者需要监视内置对象(比如Array、Object)的instanceof调用(这类对象的Symbol.hasInstance通常是不可修改的),可以把代码中的instanceof调用封装成一个工具函数,然后Spy这个函数。
示例代码:
// 第一步:在业务代码中封装instanceof检查 function isInstanceOf(obj, constructor) { return obj instanceof constructor; } // 第二步:在测试中Spy这个封装函数 const sinon = require('sinon'); const isInstanceOfSpy = sinon.spy(isInstanceOf); // 确保被测代码调用的是这个封装函数,而非直接使用instanceof function underTest(obj) { return isInstanceOfSpy(obj, Array); } underTest([1,2,3]); // 第三步:断言Spy被调用 sinon.assert.calledOnce(isInstanceOfSpy); sinon.assert.calledWith(isInstanceOfSpy, [1,2,3], Array);
注意事项
- 对于内置构造函数(如
Array、String),修改它们的Symbol.hasInstance可能会失败(因为这些属性通常是不可写/不可配置的),此时方案2会更可靠。 - 无论用哪种方案,测试完成后记得恢复原始方法/函数,避免污染其他测试用例的环境。
内容的提问来源于stack exchange,提问作者Mankind1023
相关产品推荐
相关产品推荐

