与#1512相关。
如果该属性不存在,则无需将其添加到沙箱中。 只需覆盖它。 但是,是的,如果以前可行,并且我们还没有明确表示应该更改,那么这是一种回归。
不知道我们应该在这里做什么。 更新文档,说存根不存在的值是没有意义的,不受支持,还是有可能?
如果该属性不存在,则无需将其添加到沙箱中。 只需覆盖它。
将属性添加到沙箱的好处是,sinon然后可以帮助我通过sandbox.restore()
在每次测试之间保持全局测试环境的清洁。 这是一项非常有用的功能,尤其是在处理我无法控制API的第三方库(例如Google Maps)时。 如果可以使其在3.x行中工作,那就太好了。
我也只是注意到我犯下了不提供完整例子的罪过。 我的沙盒是用2.4.1格式创建的:
let sandbox;
before(() => { sandbox = sinon.sandbox.create(); })
afterEach(() => { sandbox.restore(); })
不知道这是否重要; 对于未能尽快提供该产品,我们深表歉意。
我认为在@ZebraFlesh所描述的场景中,我宁愿使文本内容更加明确。
// not so explicit, doesn't work with [email protected]
beforeEach(function() {
const spy = sandbox.spy();
sandbox.stub(window, 'google').value({
maps: {
LatLng: x => x,
Map: spy
}
});
});
// more explicit, works with sinon<strong i="9">@2</strong>, sinon<strong i="10">@3</strong>
function setGoogleMapsFixture(sandbox) {
window.google = {
maps: {
LatLng: x => x,
Map: sandbox.spy()
}
};
}
function removeGoogleMapsFixture() {
delete window.google;
}
beforeEach(function() {
setGoogleMapsFixture(sandbox)
});
// not using afterEach, as this only needs to happen
// after the last test in this block is run
after(function() {
removeGoogleMapsFixture();
});
有了上面概述的灯具的更明确的设置,您就不需要在Sinon中使用允许对不存在的自有属性进行存根的功能。
不知道我们应该在这里做什么。 更新文档,说存根不存在的值是没有意义的,不受支持,还是有可能?
虽然我认识到在某些情况下可能很方便(例如@ZebraFlesh所描述的情况),但我认为对不存在的自身属性进行存根可能会导致测试错误,因为作者输入了错误的名称,因此测试通过了他们打算存根的现有财产。 我们的目标应该是尽可能避免发生错误的可能性,而又不要太过严格。
我认为,对不存在的自己的属性进行存根处理应该不受支持。 我们应该更新文档。
@mroderick我同意您的
所以:
或/和(?)
有了上面概述的灯具的更明确的设置,您就不需要在Sinon中使用允许对不存在的自有属性进行存根的功能。
我认为,如果您的测试装置在测试之间永不变化,那会很好。 但是,我的装置却可以。 一个简单的示例涵盖成功和失败案例:
it('handles the success case', () => {
const spy = sandbox.spy();
sandbox.stub(window, 'google').value({
maps: {
LatLng: x => x,
Map: spy
}
});
// ... test, including asserting that the spy was called
});
it('handles the failure case', () => {
const msg = 'test error';
sandbox.stub(window, 'google').value({
maps: {
LatLng: x => x,
Map: sandbox.stub().throws(new Error(msg))
}
});
// ... test, ignoring spy calls and instead focusing on error handling
});
2.x中的行为的优点在于,每次测试后,通过sandbox.restore()
可以正确清理所有内容。 使用上面概述的更明确的灯具设置示例,我想您可以删除afterEach
挂钩中的非自有属性,以实现相同的效果。
为了解决由于无意中输入现有属性的名称而导致潜在错误的问题,sinon可以修改公共API:
stub.ownValue()
:存根仅拥有属性,非拥有属性抛出stub.value()
:仅对非自有属性进行存根,对自有属性进行抛出API变得更加明确,消费者被迫为手头的任务选择合适的工具。
这与#1508中的讨论非常相关(尽管它处理的是普通存根),其中@lucasfcosta持有相反的观点-我们不应该为undefined
属性抛出。 无论我们落在何处,我都坚信_对于常规存根和沙箱来说,在存根API中我们需要保持一致。 我们不应该在一种情况下支持它,在另一种情况下也不应该支持。
目前的情况是:
因此,有一阵子我们使用了功能奇偶校验,但是后来又又失去了它。我认为这种曲折的形式对用户没有太大好处,因此我们应该进行此讨论。 尽管我确实同意Morgan的意见,因为它可能会进行更具体的测试,但我不喜欢删除两个主要版本的行为,然后再次添加它。 我认为这样做只会带来最少的噪音(针对客户的修复,此跟踪器上的问题/问题),仅用于还原此回归。
尽管我理解了不便之处,但似乎有一个简单的解决方法,只需最少的代码更改即可。
before(function() {
window.google = 'This is a placeholder for sinon to overwrite.';
});
after(function() {
delete window.google;
});
这使正弦代码保持不变。
这似乎是预期的行为,因为已经对其进行了测试。 我们应该更新文档以反映我的观点。 它具有重大意义,因此可以容忍重大变化。
@fearphage保持现状意味着对沙箱不支持存根行为,而对于常规存根
解决方案在#1557中实现
我已经阅读了各种线程,我明白了为什么会发生这种情况,但是在Typescript中,真正的痛苦是您经常在类原型上实现函数,在这种情况下,即使一切看起来都很好,sinon也会吐出虚拟对象明智的做法(因为keyof YourType
会很高兴地允许所有在原型链下定义的公共函数)。
我知道Typescript可能不是你们的优先事项,但是即使在JS中,似乎也很直观地知道myObject.callMe()
会完美地执行,而sinon.stub(myObject, "callMe")
在这种情况下则不会。 我宁愿不必去研究如何将特定对象组合在一起,这样我就知道如何对其进行存根。
考虑到类在JS中获得了更多的本机支持,我真的认为这是一个重要的用例,可以为您提供一条愉快的道路。
如果您收到一条错误消息,指出该方法未在对象上定义,则您知道该错误可能是由于原型造成的。 然后,直接使用myObject.callMe = sinon.stub();
修改对象似乎不太麻烦,恕我直言...还应避免创建清理/拆卸函数,因为原型从未更改。
是的,我想这并不是很难解决的问题,它只是给我增加了认知负担,以了解事情是如何实现的。
这似乎也出乎意料,因此我感到有必要在测试中添加注释,以解释为什么同一对象的连续两行的存根代码不同,以及为什么我手动删除了拆解中的其中一个存根,但另一个由沙箱处理。
〜谢谢您恢复这种行为〜
想要添加一个支持存根不存在属性的用例。
在我的用例中,我在配置对象上添加了一个属性。 config对象具有各种可选键,并通过从开发人员的机器中加载文件来初始化。 当我运行特定的测试时,我需要将这些键之一设置为一个已知值,然后想要按原样还原开发人员的对象。
sandbox.stub(serverSecrets, 'the_key_i_need_set').value(fakeValue)
是传达这一点的非常清晰的方法。 即使我在运行时不知道键是否为set_,也可以得到相同的行为,这是很好的。
最有用的评论
〜谢谢您恢复这种行为〜
想要添加一个支持存根不存在属性的用例。
在我的用例中,我在配置对象上添加了一个属性。 config对象具有各种可选键,并通过从开发人员的机器中加载文件来初始化。 当我运行特定的测试时,我需要将这些键之一设置为一个已知值,然后想要按原样还原开发人员的对象。
sandbox.stub(serverSecrets, 'the_key_i_need_set').value(fakeValue)
是传达这一点的非常清晰的方法。 即使我在运行时不知道键是否为set_,也可以得到相同的行为,这是很好的。