sinon.getCall(0).args [0]返回函数的结果,而不是第一个arg

时间:2017-08-03 22:01:54

标签: javascript testing lodash sinon ava

我正在使用AVA和Sinon测试一个小功能。函数看起来基本上像这样(为简洁起见编辑):

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();
});

我遇到的问题是log 1和log 2不一样。据我所知,

spy.getCall(n).args[m]

从第n次调用返回传递给spied on函数的第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] a.k.a" log 2"实际上是回归"选择"在_.defaultsDeep运行后变为。这感觉就像Sinon图书馆中的一个错误,但更可能是我做错了什么。非常感谢帮助,感谢先进!

1 个答案:

答案 0 :(得分:0)

您遇到的根问题是对参数的引用(在本例中为opts)与您使用值操作的对象相同(因为所有对象都通过JavaScript中的引用传递)。实际上,您正在更改opts指向的物理位置。

由于Sinon没有对您传入的对象进行“快照”或“复制”(它只返回您传入的相同对象引用),因此您也会影响Sinon返回的内容。 / p>

要解决此问题,代码应该类似于

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

Object.assign将创建一个新对象(以及内存中的关联位置)。因此,它会保持opts不受影响,因此您可以检查传入的内容。