我无法存根要在打字稿中测试的方法所使用的方法。为了清楚起见,我在示例中删除了很多方法本身,但是基本上我有一个getServiceWithRetry方法来调用getService方法。

即。

export function getServiceWithRetry(name:string, triesLeft:number) {
    //do stuff
    getService(name)
    //do more stuff
}

export function getService(name:string) {
    //lookup stuff
}


这作为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()
})


注意:对于不熟悉蓝鸟诺言的人,.then(function(value){}, function(error){})方法处理如果诺言成功和诺言被拒绝的情况。

最佳答案

问题在于,使用sinon.stub(Lookup, 'getService')会使您在测试中持有的Lookup变量的内部发生变异,然后从该变量获取方法。在您的Lookup模块中,该函数只是直接从其本地范围中查找getService。从外部看,我认为您没有办法弄乱该示波器,因此恐怕没有简单的魔术解决方案。

通常,您通常无法在测试中很好地模拟单个模块的各个部分。您需要对此进行一些重组,并且有一些选择:


完全分别测试它们。将getServiceWithRetry更改为通用的retry方法,例如因此您可以像retry(nTimes, getService, "serviceName")retry(() => getService("serviceName"), nTimes)这样称呼它。如果这样做是可行的(即,如果它与getService的联系不太紧密),则可以轻松地自己进行测试:

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


如果希望在其他地方仅调用一个getServiceWithRetry,则可以轻松构建一个:var getServiceWithRetry = (arg, triesLeft) => retry(getService, tries)
放弃,一起测试。这意味着存根getService依赖的内容,而不是直接存根。这取决于您要从测试中获得的粒度级别,但是如果此代码很简单并且可以进行更粗略的测试,则这可能是一个简单的选择。

即使您仍然将它们分开,您也可能希望这样做,以获得单元和集成测试以获得额外的覆盖范围。如果它们之间存在一些更复杂的交互,则这是双重事实。
从我所看到的情况来看,在这种情况下可能不相关,但在其他情况下,则有点像将待测方法(getServiceWithRetry)放在类中,并使用依赖项注入。您将创建一个类,该类在其构造函数中使用依赖项(getService方法),将其存储在内部,然后在以后对结果对象调用方法时使用它。在生产代码中,必须使用其他方法将它们正确粘合在一起,然后才能在测试中通过存根传递。
对于这种情况,我也期望过高,但是您可以将getService拉入Lookup导入的完全独立的模块中,并在测试过程中使用Rewire之类的东西将其替换为其他模块。

这实际上与依赖项注入选项非常相似,它使您的生产代码更简单,但以使您的测试代码更复杂和神奇为代价。

关于javascript - Sinon-如何对要测试的方法调用的方法进行 stub ,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/39988909/

10-11 17:14