Javascript Sinon-如何存根我要测试的方法调用的方法
我在存根一个我想在typescript中测试的方法所使用的方法时遇到问题。为了清晰起见,我在示例中去掉了很多方法本身,但基本上我有一个调用Javascript Sinon-如何存根我要测试的方法调用的方法,javascript,typescript,sinon,Javascript,Typescript,Sinon,我在存根一个我想在typescript中测试的方法所使用的方法时遇到问题。为了清晰起见,我在示例中去掉了很多方法本身,但基本上我有一个调用getService方法的getServiceWithRetry方法 即 这将作为Lookup导入到我的测试中。如果我在测试中调用getService,我可以成功地删除getService方法,但是当我运行getServiceWithRetry时,它调用实际的getService方法,而不是存根。有人知道我做错了什么吗 it("test", function(
getService
方法的getServiceWithRetry
方法
即
这将作为Lookup
导入到我的测试中。如果我在测试中调用getService
,我可以成功地删除getService方法,但是当我运行getServiceWithRetry
时,它调用实际的getService
方法,而不是存根。有人知道我做错了什么吗
it("test", function(done) {
let serviceStub = sinon.stub(Lookup, 'getService')
serviceStub.returns(Promise.resolve("resolved"))
//this uses the stub
Lookup.getService("name").then(function(value) {
console.log("success: "+value)
}, function(error) {
console.log("error: "+error)
})
//this calls the actual method, not the stub as I would expect it to
Lookup.getServiceWithRetry("serviceName", 4).then(function(value) {
console.log("success: "+value)
}, function(error) {
console.log("error: "+error)
})
done()
})
注意:对于那些不熟悉bluebird承诺的
。然后(函数(值){},函数(错误){})
方法处理承诺成功和承诺被拒绝时发生的情况。问题在于sinon.stub(查找,'getService'))
您正在变异测试中保存的查找变量的内部,然后从该变量获取方法。在查找模块中,函数只是直接从其本地范围查找getService
。从外部看,我不认为有任何方法可以搞乱这个范围,所以恐怕没有简单的魔法解决办法
通常,您不能在测试中很好地模拟单个模块的各个部分。您需要对其进行一些重组,有几个选项:
- 完全分开测试。将getServiceWithRetry更改为通用的
方法,例如,您可以像retry
或retry(nTimes,getService,“serviceName”)
retry(()=>getService(“serviceName”),nTimes)那样调用它。如果这样做是可行的(即,如果它没有太多地绑定到
),那么您可以轻松地自行测试:getService
如果您想在其他地方只调用一个getServiceWithRetry,可以轻松构建一个:var myStub = sinon.stub(); myStub.onCall(0).throw("fail once"); myStub.onCall(0).throw("fail twice"); myStub.returns(true); // then return happily expect(retry(myStub, 1)).to.throw("fail twice"); // gives up after one retry expect(retry(myStub, 5)).to.return(true); // keeps going to success
var getServiceWithRetry=(arg,triesLeft)=>retry(getService,tries)
- 放弃,一起测试。这意味着剔除
依赖的内容,而不是直接剔除。这取决于您希望从测试中获得的粒度级别,但是如果此代码很简单,并且您可以进行更粗略的测试,那么这可能是一个简单的选择 即使您已经将它们分开,您也可能希望这样做,以获得额外覆盖的单元和集成测试。如果他们之间有一些更复杂的相互作用,这是双重事实getService
- 从我所看到的情况来看,在这种情况下可能不相关,但在其他情况下,类似于在类中测试方法(getServiceWithRetry),并使用依赖项注入。您将创建一个类,该类在其构造函数中接受依赖项(getService方法),在内部存储该依赖项,并在以后调用结果对象上的方法时使用它。在您的生产代码中,其他一些东西必须正确地将它们粘合在一起,然后在您的测试中,您可以传递一个存根
- 对于这种情况,我认为也有点过头了,但是您可以将
拉入一个完全独立的模块中进行查找导入,并在测试过程中使用类似的方法将其交换到另一个模块中 这与依赖项注入选项非常相似,使生产代码更简单,但代价是使测试代码更复杂、更神奇getService
export function getServiceWithRetry(name:string, triesLeft:number) {
//do stuff
getService(name)
//do more stuff
}
致:
这样,当您调用
Lookup.getServiceWithRetry()
时,getService()
调用将指向Lookup.getService()
,而不是位于导出源模块中的getService()
由于您使用的是TypeScript,所以最好使用(npm安装--保存ts mockquito
)
ts mockito
支持类型
然后,您可以模拟您的类,如(从自述文件中,稍加修改):
export function getServiceWithRetry(name:string, triesLeft:number) {
//do stuff
getService(name)
//do more stuff
}
export function getServiceWithRetry(name:string, triesLeft:number) {
//do stuff
this.getService(name)
//do more stuff
}
// Creating mock
let mockedFoo:Foo = mock(Foo);
// Getting instance from mock
let foo:Foo = instance(mockedFoo);
// Using instance in source code
foo.getBar(3);
foo.getBar(5);
// Explicit, readable verification
verify(mockedFoo.getBar(3)).called();
verify(mockedFoo.getBar(5)).called();
when(mockedFoo.getBar(4)).thenReturn('three');