在运行测试时,我有时想为我的测试提供一个API。我希望仅在测试期间定义此api,因此我希望确保sinon.restore()
删除此测试api。这不是替换现有的JS API。(如。不是像window.requestAnimiationFrame
那样的东西。假定此API是全局存在的。(如。在全局/window对象上)
现在,如果我不关心删除这个API,在测试完成后,我将做以下操作:
globalAPIObject.someTestApi = sinon.fake.returns('something');
然而sinon.restore
不会/不能删除globalAPIObject。someTestApi .
我希望能够像stub
一样使用fake。(但sinon不提供)
// !! this API doesn't exist !!
sinon.fake(globalAPIObject, 'someTestApi').returns('something');
// !! this API doesn't exist !!
所以我用stub代替:
// This doesn't work if globalAPIObject.someTestAPi doesn't already exist.
sinon.stub(globalAPIObject, 'someTestApi').returns('something');
然而,这只适用于替换已经存在的道具/函数,所以我必须这样做:
globalAPIObject.someTestApi = () = {};
sinon.stub(globalAPIObject, 'someTestApi').returns('something');
这是不理想的。(如globalAPIObject。someTestApi不会在测试结束时被sinon.restore()删除。而且我宁愿只写一行)
因为我猜提供一个不存在的API是很多人想做的事情,我猜我错过了一些明显的东西。
假冒/存根/模拟新API的最佳方式是什么?恢复之后删除它的所有痕迹?
总之,使用sinon.restore()
无法做到这一点。我们明确地制作了API,试图替换不存在的道具,但我们在sinon团队对此进行了更长时间的讨论,最终得出结论,我们应该添加sinon.define()
之类的东西。然而,没有人把这个功能请求变成一个实际的问题,所以如果我是你,我会把这个作为你的功能请求提交给Sinon Github跟踪器。很多人会喜欢这个功能,它真的不是很难实现,所以只要让它可见:)
要真正做到这一点,使用今天现有的机器,我可能只是做在评论中提到的:使用你的测试框架之前/之后挂钩设置和拆除手动构建的存根。
如果我要自己做,我可能会重新编写代码,以便能够将API注入到您的模块中,而不是依赖全局变量。这是另一种思想流派,所以,不管你的船撞了什么
考虑到'oligofren'有助于澄清这个问题。Stub不是我们的用例,我们只是扩展了它。
// sinonExtensions.js
import sinon from "sinon";
if (sinon.stub !== enhancedStub)
{
sinon.originalStub = sinon.stub;
sinon.stub = enhancedStub;
}
function enhancedStub(obj, method)
{
if (!obj)
return sinon.originalStub();
if (!obj[method])
obj[method] = () => { };
return sinon.originalStub(obj, method);
}
// TODO: enhance sinon.restore to return non-existing methods to undefined
与其他sinon导入的内容一起导入:
import sinon, { mock } from "sinon";
import sinonChai from 'sinon-chai';
import 'sinonExtensions.js';
chai.use(sinonChai);
这对我们当前使用的所有sinon.stub都是有益的。
现在这个快乐的工作:
sinon.stub(globalAPIObject, 'someTestApi').returns('something');