如何确保仅在给定特定参数的情况下调用方法一次

时间:2018-03-14 11:12:54

标签: javascript java promise sinon ava

我有一个名为Feature的类,它包含以下方法setUser(boolean),execute(),doExecute() 并且根据下面描述的参数,当我调用execute()方法时,doExecute()方法应该只被调用一次。

我尝试测试doExecute()方法在下面的代码中仅使用sinon调用一次,但是我收到一条错误消息:doExecute()方法被调用为零次。

请让我知道如果正确调用doExecute()一次是否正确检查

t.context.clock = sinon.useFakeTimers();
const domain = 'testDomain';
const delayInMillis = 0;
const delayInSecs = delayInMillis / 1000;
const feature = new Feature(domain, delayInMillis);
feature.setUser(false);

const p = feature.execute()
 .then(() => sinon.spy(feature.doExecute()))
 .then(() => t.pass());

sinon.assert.callCount(sinon.spy(feature.doExecute()),1);
t.context.clock.restore();

return p;
});

2 个答案:

答案 0 :(得分:0)

首先,sinon.spy()接受function作为参数,然后传递函数的结果。

// wrong
sinon.spy(feature.doExecute());

// correct
sinon.spy(feature.doExecute);

接下来,您需要将间谍存储到变量中以供日后参考。在你的代码中,你每次只是创造新的间谍。

const featureDoExecuteSpy = sinon.spy(feature.doExecute);

// some code

sinon.assert.callCount(featureDoExecuteSpy, 1);

答案 1 :(得分:0)

这有很多问题。

正如他所指出的那样,你只是在你的断言中创建一个新的间谍。显然,新间谍的呼叫计数为零。您需要确保断言是指与正在测试的代码调用的相同的间谍实例。

然而,同样错过的关键是,间谍必须传递给你正在测试的代码。这就是为什么`sinon.spy()'的usual form接受一个对象后跟一个方法名称的原因。它用一个封装原始对象的间谍替换该对象上的方法:

// wrong
sinon.spy(feature.doExecute());

// still wrong
sinon.spy(feature.doExecute);

// correct
sinon.spy(feature, 'doExecute');

然后,您可以访问该对象上的间谍以进行断言。您无需将其存储在本地变量中:

sinon.assert.callCount(feature.doExecute, 1);

另一个问题:您的断言不等待feature.execute解决的承诺。这意味着如果在doExecute内的某些异步操作之后调用execute,则您的断言发生得太早。因此,它需要在then后跟其他人一样(请注意,由于我稍后会解决的其他问题,此代码仍然无效):

const p = feature.execute()
 .then(() => sinon.spy(feature, 'doExecute'))
 .then(() => t.pass())
 .then(() => sinon.assert.callCount(feature.doExecute,1));

更多问题......您使用假定时器非常奇怪,并且我很难判断feature.execute()返回的承诺是否会解决。

如果需要计时器才能解决?它不会。因为你永远都不会打电话给计时器。我不知道t.pass()做了什么,但由于它被链接到feature.execute()返回的承诺,如果你不在其他地方勾选计时器,它将永远不会被调用。由于同样的原因,你的代码也不会造成你的间谍。

你需要在调用feature.execute()之前创建你的间谍,并且可能在之后调用t.pass() ,如果它确实是勾选你的方法假计时器:

sinon.spy(feature, 'doExecute')

const p = feature.execute()
 .then(() => sinon.assert.callCount(feature.doExecute,1));

t.pass();

最后,我不知道你正在使用什么测试框架,但是你通常希望在总是执行的块中恢复假定时器和其他全局状态,无论你的测试是否成功。这样可以确保失败的测试不会让废话悬挂在其他测试中。为此,Mocha有方法beforeEachafterEach

beforeEach(function() {
    t.context.clock = sinon.useFakeTimers();
});

afterEach(function() {
    t.context.clock.restore()
});

it('whatever your test name is', function() {
    const domain = 'testDomain';
    const delayInMillis = 0;
    const delayInSecs = delayInMillis / 1000;
    const feature = new Feature(domain, delayInMillis);

    sinon.spy(feature, 'doExecute')

    const p = feature.execute()
      .then(() => sinon.assert.callCount(feature.doExecute,1));

    t.pass();

    return p;
});