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

Kai*_*izo 17 javascript unit-testing sinon

我有这样的功能:

function foo () {
    obj.method(1);
    obj.method(2);
    obj.method(3);
}
Run Code Online (Sandbox Code Playgroud)

为了测试它,我想做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();
});
Run Code Online (Sandbox Code Playgroud)

使用该系统,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();
});
Run Code Online (Sandbox Code Playgroud)

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

怎么能实现这一目标?

Kai*_*izo 5

与往常一样,当测试出现奇怪的情况时,问题就出在正在测试的代码中

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

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

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

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

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

代码会是这样的:

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

dataGenerator.generate = function () {
    return [1,2,3];
};
Run Code Online (Sandbox Code Playgroud)

和测试:

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)
});
Run Code Online (Sandbox Code Playgroud)

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