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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21161340/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 20:15:00  来源:igfitidea点击:

How to test multiple calls to the same function with different params?

javascriptunit-testingsinon

提问by Kaizo

Supose I have a function like this:

假设我有一个这样的功能:

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

To test it I want to do 3 tests (using Mocha TDD and Sinon):

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

Using this system sinon fails with "unexpected call" message on each test.

使用此系统 sinon 在每次测试中都失败并显示“意外呼叫”消息。

I've solved it joining the tree tests into one:

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

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

But i want to have three tests and not one with three assertions/expectations.

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

How can this be achieved?

如何做到这一点?

采纳答案by Kaizo

As always, when there is something weird about a test the problem is in the code being tested.

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

In this case we suffer from coupling. Currently the function has two responsibilities:

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

  • Decide the data to use.
  • Call the method with the data.
  • 决定要使用的数据。
  • 使用数据调用方法。

To solve this we must divide the responsibilities in two functions/objects/classes and then test each one separately. For example one possibility could be:

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

  • The first function (one that generates and returns the data) would be tested checking that the returned data matches our expectations.

  • The second function (our original one) would have a test checking that it calls the data generator, then a test checking that it sends the data correctly to the expected function and a third one checking that it calls the functions as many times as needed by the data.

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

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

The code would be something like this:

代码将是这样的:

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

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

And the tests:

和测试:

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

Note that the third test only checks the amount of times the method is called. The second test has already checked that the data is passed correctly and the fourth tests the data itself.

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

回答by reyuto

This is a bloated version, but this solution might work. Not sure if you still need it, but I am just adding it here. http://jsfiddle.net/reyuto/jhkL7j34/

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