2017-08-03 49 views
0

我正在測試一個使用AVA和Sinon的小函數。功能基本上看起來像這樣(編輯爲簡潔起見):sinon.getCall(0).args [0]返回函數的結果,而不是首先arg

mergeDefaults: function (opts) { 
    **console.log('log 1 ->', opts);** 
    opts = _.defaultsDeep(opts, defaultOptions); 
    return opts; 
} 

我寫了一個測試,以確保正確的參數傳遞到_.defaultsDeep。

test.before(t => { 
    sandbox = sinon.sandbox.create(); 
    defaultsDeepSpy = sandbox.spy(_, 'defaultsDeep'); 
    mergeDefaults(Object.assign({}, testOptions)); 
}); 

test('mergeDefaults runs _.defaultsDeep with the correct parameters', t => { 
    **console.log('log 2 ->', defaultsDeepSpy.getCall(0).args[0]);** 
    t.is(defaultsDeepSpy.getCall(0).args[0], testOptions); 
    t.is(defaultsDeepSpy.getCall(0).args[1], defaultOptions); 
}); 

test.after.always(t => { 
    sandbox.restore(); 
}); 

我遇到的問題是,日誌1和日誌2是不一樣的。據我所知,

spy.getCall(n).args[m] 

返回傳遞給spied on函數從第n次調用該函數的第m個參數。然而,在這種情況下,log 2實際上是返回函數的結果,而不是第一個參數。

的選擇對象是這個樣子:

testOptions = { 
    key1: 11, 
    key2: 22, 
    key3: 33 
} 
defaultOptions = { 
    key1: 1, 
    key2: 2, 
    key3: 3, 
    key4: 4, 
    key5: 5 
} 

但console.logs這個樣子:

log 1 -> testOptions = { 
    key1: 11, 
    key2: 22, 
    key3: 33 
} 
log 2 -> testOptions = { 
    key1: 11, 
    key2: 22, 
    key3: 33, 
    key4: 4, 
    key5: 5 
} 

所以spy.getCall(0).args [0]又名「日誌2「實際上是在_.defaultsDeep運行之後返回」opts「變成的。這感覺就像是Sinon庫中的一個bug,但更可能是我做錯了什麼。非常感謝幫助,感謝先進!

回答

0

您遇到的根本問題是對參數的引用(在本例中爲opts)與您使用值操作的對象相同(因爲所有對象都是通過JavaScript中的引用傳遞的)。實際上,您正在更改opts指向的物理位置。由於Sinon不會對你傳入的對象進行「快照」或「複製」(它只是返回傳入的相同對象引用),所以你也影響Sinon返回的內容。

爲了解決這個問題的代碼應該看起來像

mergeDefaults: function (opts) { 
    return _.defaultsDeep(Object.assign({}, opts), defaultOptions); 
} 

Object.assign將創建(在內存和相關的地方)的新對象。因此,它將保持opts不變,因此您可以檢查通過的內容。