2017-06-26 47 views
0

我有一些使用sinon存根的问题,它可能来自我如何在模块上实现命名空间,我期待存根。直接在原型上定义的方法按我所期望的那样存在。sinon stub命名空间函数

...my module.js 
const Constructor = require('./constructor') //...just exports a singleton 

/* Need to namespace some of my functions and retain the `this` context */ 

Object.defineProperty(Constructor.prototype, 'es', { 
    get: function() { 
    return { 
     method: require('./implementations/doesSomething.js').bind(this) 
    } 
    } 
}); 

module.exports = Constructor; 




/* ...testFile.js */ 
const Constructor = require('./constructor'); 
const instance = new Constructor(); 
const sinon = require('sinon'); 

sinon.stub(instance.es, 'method', function() { 
    return 'hijacked original method' 
}); 
+0

什么错误是你越来越? – Arcath

+0

@Arcath我没有收到任何错误,它根本就不存在任何方法。我也注意到,如果我把console.log检查它是否确实是一个sinon存根,而不是。 –

回答

1

如前所述on the Sinon issue tracker,这里的问题是,使用普通电话Object.defineProperty(obj, 'prop')做了比使用赋值(obj['prop'] = ...)清楚地创造它别的。

一般来说,如果你尝试定义你的财产没有Object.defineProperty它将是可毁灭的,但使用defineProperty(不创建一个特殊的配置)将使它不可能残留的属性。原因很简单,default values for writeable and configurablefalse!你不能delete他们或改变他们。如果你不能这样做,那么Sinon不会帮助你。所以,一般来说,你需要在你的属性定义中添加writeable: true, configurable: true

现在有一件事我忘了最初回答: 你是不是想换就Constructor.prototype.es.method功能 - 你正在试图总结是吸气的属性返回的对象上的功能es。那永远不会工作。 为什么?只是因为返回的对象是从来没有一样的。您每次创建一个围绕method的新对象。如果您确实需要更换/存根method属性,则实际上需要替换整个Constructor.prototype.es属性。如果你需要这个命名空间,可以大大简化这一点,也使存根,就像这样:

Constructor.prototype.es = {}; 

Object.defineProperty(Constructor.prototype.es, 'method', { 
    get: function() { 
    return someFunction.bind(this); 
    }, 
    writeable: true, 
    configurable:true 
} 

的扩展,完全工作示例(Gist for download):

// constructor.js 
 
const someFunction = function(){ 
 
    return this.value; 
 
} 
 

 
function Constructor(){ }; 
 
Constructor.prototype.es = { value : 100 }; 
 

 
Object.defineProperty(Constructor.prototype.es, 'method', { 
 
    get: function() { 
 
    return someFunction.bind(this); 
 
    }, 
 
    writeable: true, 
 
    configurable:true 
 
}); 
 

 
// test.js 
 
const instance = new Constructor(); 
 

 
console.log(instance.es.method()) // => 100 
 

 
// using this won't work: 
 
// sinon.stub(instance.__proto__.es, 'method').returns(42); 
 
// because the getter is returning a _new_ function each time 
 
// therefore you need to attack the actual getter function: 
 

 
const stub = sinon.stub(instance.__proto__.es, 'method').value(()=>42); 
 
console.log(instance.es.method()) // => 42 
 
stub.get(()=>()=>84); 
 
console.log(instance.es.method()) // => 84 
 
stub.restore(); 
 
console.log(instance.es.method()) // => 100 
 

 
// the above is working on the prototype, can't we do this on the instance? 
 
// yes, we can, but remember that the `es` object is shared, so we 
 
// can avoid modifying it by shadowing it further down the prototype 
 
instance.es = { method: sinon.stub().returns(256) }; 
 
console.log(instance.es.method()) // => 256 
 
delete instance.es 
 
console.log(instance.es.method()) // => 100
<script src="https://unpkg.com/[email protected]/pkg/sinon.js"></script>

+0

嗨,感谢您的帮助,我真的很感激。虽然我的构造函数是一个单例,但它始终是同一个对象。如我错了请纠正我。 我实现了这个解决方案,我得到这个问题 ** TypeError:尝试在checkWrappedMethod(node_modules/sinon/lib/sinon/util/core/wrap-method.js:41: 21)'** ,因为逻辑正在寻找当前配置中未指定的值prop。 –

+0

我将添加一个运行例如,当我进入我添加了一个完全的运行示例工作 – oligofren

+0

: https://gist.github.com/515baa042a7c06cdd18c73ec751ff994 它演示了各种不同的技术和有很好的注释。 – oligofren