如何使用不同的参数测试对同一函数的多个调用?

时间:2014-01-16 12:06:30

标签: javascript unit-testing sinon

Supose我有这样的功能:

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();
});

但我希望有三个测试,而不是一个有三个断言/期望的测试。

如何实现这一目标?

2 个答案:

答案 0 :(得分:3)

与往常一样,当测试有些奇怪时,问题出在被测试的代码中

在这种情况下,我们遭受耦合。目前该职能有两个职责:

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

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

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

  • 第二个函数(我们原来的函数)将有一个测试检查它调用数据生成器,然后测试检查它是否正确地将数据发送到期望的函数,第三个函数检查它是否调用函数根据数据需要多次。

代码将是这样的:

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)
});

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

答案 1 :(得分:0)

这是一个臃肿的版本,但这个解决方案可能有效。不确定你是否仍然需要它,但我只是在这里添加它。 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();
    });