2017-08-03 84 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不变,因此您可以检查通过的内容。