如何使用Sinon监视代码中变量调用的toString方法?
如何用Sinon监视变量调用的
toString方法 这个问题的核心在于**toString的调用对象到底是谁**——不同类型的变量,调用的toString方法来自原型链的不同位置,咱们分情况来解决:
情况1:somevar是自定义对象/类实例
如果somevar是你能控制的对象(比如自己创建的空对象、某个类的实例),直接在实例本身或者它的类原型上监视toString就可以:
假设你的业务代码是这样的:
function checkValue(somevar) { return somevar.toString().length === 2; }
对应的测试代码可以这么写:
const sinon = require('sinon'); const assert = require('assert'); describe('checkValue', () => { it('should invoke toString on the target object', () => { // 1. 创建测试用的对象 const testObj = {}; // 2. 监视这个对象的toString方法 const toStringSpy = sinon.spy(testObj, 'toString'); // 3. 执行业务函数 checkValue(testObj); // 4. 断言方法被调用 assert.ok(toStringSpy.calledOnce); // 5. 记得恢复原始方法,避免影响其他测试 toStringSpy.restore(); }); // 如果是类实例的情况 it('should invoke toString on MyClass instance', () => { class MyClass {} const instance = new MyClass(); // 监视类原型上的toString const protoSpy = sinon.spy(MyClass.prototype, 'toString'); checkValue(instance); assert.ok(protoSpy.calledOnce); protoSpy.restore(); }); });
情况2:somevar是原始值(数字、字符串、布尔值)
原始值(比如12、'ab')在调用toString时会被自动"装箱"成对应的包装对象(Number、String等),所以要监视对应包装类型原型上的toString:
比如测试数字类型的输入:
describe('checkValue', () => { it('should invoke Number.prototype.toString for number inputs', () => { // 监视Number原型上的toString const numToStringSpy = sinon.spy(Number.prototype, 'toString'); checkValue(12); // 数字12会被装箱为Number对象,调用Number.prototype.toString assert.ok(numToStringSpy.calledOnce); numToStringSpy.restore(); }); // 字符串类型同理 it('should invoke String.prototype.toString for string inputs', () => { const strToStringSpy = sinon.spy(String.prototype, 'toString'); checkValue('ab'); assert.ok(strToStringSpy.calledOnce); strToStringSpy.restore(); }); });
为什么监视Object.prototype无效?
因为原始值的包装类型(比如Number)的toString是重写过自身原型的方法,并不会直接调用Object.prototype.toString(虽然Number.prototype继承自Object.prototype,但调用时会优先取自身原型的方法),所以监视Object.prototype自然抓不到调用。
额外技巧:Stub返回特定值
如果需要让toString返回指定长度的字符串来测试分支逻辑,可以用sinon.stub代替spy:
const toStringStub = sinon.stub(testObj, 'toString').returns('xy'); checkValue(testObj); // 会进入length===2的分支
内容的提问来源于stack exchange,提问作者Mankind1023
相关产品推荐
相关产品推荐

