如何为有问题的代码编写存根 [单元测试]

3

如果你是对编写单元测试和“模拟”概念不熟悉的新手,那么请放心。我有一个基本函数'addPercentSign',如果用户输入在50-100之间,则会将百分号添加到用户输入中:

    addPercentSign: function (oEvent, control) {
        var inputVal = oEvent.getParameters().value;
        var inputNumber = parseFloat(inputVal);

        if (inputNumber) {

            if (inputNumber < 50 || inputNumber > 100) {
                return null;
            } else {
                var finalVal = inputNumber.toFixed(1);
                var finalOutput = finalVal + "%";

//Error: cannot setValue of undefined. How can I 'stub' the line below?
                control.learningCurve.setValue(finalOutput);

                return finalOutput;
            };
        }
    }
问题

我面临的问题是,当我为这个函数编写单元测试时,我无法测试返回的值(finalOutput),因为它之前的那行代码会返回一个错误,因为它依赖于DOM元素(control.learningCurve)来设置一个值。由于这是一个单元测试,我必须将这个函数与任何依赖项隔离开来。

因此,我需要“模拟”“setValue”调用。我想创建一个存根可能是有意义的,但我不确定怎么做?

这是我想要测试上述函数(addPercentSign)的单元测试代码:

function (formatter, viewControls) {
    "use strict";

    var testEvent = {
        getParameters : function() {
                return {value : 50}
        }
    }

    QUnit.module("Formatter Functions");
    QUnit.test("Add Percent Sign", function (assert) {

    assert.ok(formatter.addPercentSign(testEvent, viewControls) == '50.0%', "Percent Sign Added: Pass");

    });
}

问题

如何模拟setter以便在没有DOM依赖的情况下对此函数进行单元测试?

control.learningCurve.setValue(finalOutput)
3个回答

1

Sinon 可以用作测试替身。

这个例子使用了 sinon stub。

sinon.stub(control.learningCurve, 'setValue').returns('value that you need');

把编辑:

function (formatter, viewControls) {
"use strict";

    sinon.stub(control.learningCurve, 'setValue').returns('value that you need');

    var testEvent = {
        getParameters : function() {
                return {value : 50}
        }
    }

    QUnit.module("Formatter Functions");
    QUnit.test("Add Percent Sign", function (assert) {

    assert.ok(formatter.addPercentSign(testEvent, viewControls) == '50.0%', "Percent Sign Added: Pass");

    });
}

谢谢,您能演示一下如何将其插入到上面的单元测试中吗?看起来第一个参数是control.learningCurve对象,而第二个参数是我想要“存根”的函数? - Kode_12
是的,它可以将 sinon.stub(object, "method") 作为参数传递。Sinon 文档中有更多关于如何使用 stub 的细节。 - SafeHouse
谢谢,但我发现他们的文档对于刚学习模拟、存根和间谍的人来说非常难以理解。 - Kode_12

0

我不确定,因为我不是JS Ninja,但我认为这应该不难。

你想要使用的方法在一个名为“learningCurve”的对象内,该对象位于“control”对象内。

如果控件在您的格式化程序中,则可以这样做:

formatter.control = {};
formatter.control.learningCurve = {};
formatter.control.learningCurve.setValue = function() {
    return something_to_return;
}   

assert.ok(formatter.addPercentSign(testEvent, viewControls) == '50.0%', "Percent Sign Added: Pass");

如果它不在格式化程序内,那么通过创建控件的新实例并替换上述内容来执行此操作。


0

我认为单元测试的主要附加价值之一是让你意识到代码可以重构的地方。在您的情况下,有两个不同的问题:添加%和修改DOM。通过将这两个问题重构为各自的函数,您可以对逻辑进行单元测试,而无需模拟任何内容。

//Formerly addPercentSign
inputChanged: function (oEvent, control) {
    var inputVal = oEvent.getParameters().value;
    var inputNumber = parseFloat(inputVal);
    var formattedNumber = addPercentSign(inputNumber);
    control.learningCurve.setValue(formattedNumber);
}

function addPercentSign(inputNumber) {
    if (inputNumber < 50 || inputNumber > 100) {
        return inputNumber;
    }
    var finalVal = inputNumber.toFixed(1);
    return finalVal + "%";
}

现在你可以轻松测试 addPercentSign。你也可以对 inputChanged 进行单元测试,但那只是对 JavaScript 框架进行单元测试。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接