【问题标题】:How to test multiple calls to the same function with different params?如何使用不同的参数测试对同一函数的多次调用?
【发布时间】:2014-02-05 08:00:42
【问题描述】:

假设我有这样的功能:

function foo () {
    obj.method(1);
    obj.method(2);
    obj.method(3);
}

为了测试它,我想做 3 次测试(使用 Mocha TDD 和 Sinon):

test('medthod is called with 1', function () {
    var expectation = sinon.mock(obj).expects('method').once().withExactArgs(1);
    foo();
    expectation.verify();
});

test('medthod is called with 2', function () {
    var expectation = sinon.mock(obj).expects('method').once().withExactArgs(2);
    foo();
    expectation.verify();
});

test('medthod is called with 3', function () {
    var expectation = sinon.mock(obj).expects('method').once().withExactArgs(3);
    foo();
    expectation.verify();
});

使用这个系统 sinon 每次测试都会失败,并显示“意外调用”消息。

我已经解决了将树测试合二为一的问题:

test('medthod is called with 1, 2 and 3', function () {
    var mock = sinon.mock(obj);
    mock.expects('method').once().withExactArgs(1);
    mock.expects('method').once().withExactArgs(2);
    mock.expects('method').once().withExactArgs(3);
    foo();
    mock.verify();
});

但我想要三个测试,而不是一个包含三个断言/期望的测试。

如何做到这一点?

【问题讨论】:

  • 每次测试后你都恢复了模拟吗?
  • @CarlosCampderrós var obj 在 setup 函数中声明,因此在此测试中不需要恢复。
  • 我不确定这个问题不仅仅是理论上的问题。您正在告诉Sinon,您希望该方法被调用 once().withExactArgs(1) 所以预期是正确的。也许这需要重构你的代码?
  • 我认为您需要查看 spy.withArgs。 documentation 似乎暗示您只能监视那些带有特定参数的调用。可能有用。
  • @Sonata 我能想到的重构是将三个调用分成三个方法,然后调用这三个方法,不过希望能找到更好的选择。如果调用次数是动态的,则此系统可能会失败。

标签: javascript unit-testing sinon


【解决方案1】:

与往常一样,当测试出现异常时,问题出在被测试的代码中

在这种情况下,我们会遇到耦合问题。目前该功能有两个职责:

  • 决定要使用的数据。
  • 使用数据调用方法。

为了解决这个问题,我们必须将职责划分为两个函数/对象/类,然后分别进行测试。例如,一种可能是:

  • 将测试第一个函数(生成和返回数据的函数),检查返回的数据是否符合我们的预期。

  • 第二个函数(我们的原始函数)将进行测试检查它是否调用了数据生成器,然后进行测试检查它是否将数据正确发送到预期的函数,第三个检查它是否调用了函数数据需要多少次。

代码是这样的:

function foo() {
    dataGenerator.generate().forEach(function (item) {
        obj.method(item);
    })
}

dataGenerator.generate = function () {
    return [1,2,3];
};

还有测试:

test('generateData is called', function () {
    var expectation = sinon.mock(dataGenerator).expects('generate').once();
    foo();
    expectation.verify();
});

test('method is called with the correct args', function () {
    var expectedArgs = 1;
    sinon.stub(dataGenerator, "generate").returns([expectedArgs]);
    var expectation = sinon.mock(obj).expects('method').once().withExactArgs(expectedArgs);
    foo();
    expectation.verify();
});

test('method is called as many times as the amount of data', function () {
    sinon.stub(dataGenerator, "generate").returns([1,2]);
    var expectation = sinon.mock(obj).expects('method').twice();
    foo();
    expectation.verify();
});

test('dataGenerator.generate returns [1,2,3]', function () {
    var expected = [1,2,3];
    var result = dataGenerator.generate();
    assert.equal(result, expected)
});

请注意,第三个测试只检查方法被调用的次数。第二个测试已经检查数据是否正确传递,第四个测试数据本身。

【讨论】:

    【解决方案2】:

    这是一个臃肿的版本,但此解决方案可能有效。不知道你是否还需要它,但我只是在这里添加它。 http://jsfiddle.net/reyuto/jhkL7j34/

        obj = {
            method: function (param) {}
        };
    
        function foo() {
            obj.method(1);
            obj.method(2);
            obj.method(3);
        }
    
        mock = sinon.mock(obj);
    
        QUnit.test('method is called with 1', function () {
            var expectation1 = mock.expects('method').once().withExactArgs(1);
            var expectation2 = mock.expects('method').atLeast(2);
            foo();
            expectation1.verify();
            expectation2.verify();
        });
    
        QUnit.test('method is called with 2', function () {
            var expectation1 = mock.expects('method').atLeast(1);
            var expectation2 = mock.expects('method').once().withExactArgs(2);
            var expectation3 = mock.expects('method').atLeast(1);
            foo();
            expectation1.verify();
            expectation2.verify();
            expectation3.verify();
        });
    
        QUnit.test('method is called with 3', function () {
            var expectation1 = mock.expects('method').once().withExactArgs(3);
            var expectation2 = mock.expects('method').atLeast(2);
            foo();
            expectation1.verify();
            expectation2.verify();
        });
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-08
      • 2014-02-19
      • 2021-02-06
      • 1970-01-01
      • 1970-01-01
      • 2017-01-19
      相关资源
      最近更新 更多