2017-06-26 44 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