【问题标题】:How can I stub a problematic piece of code [Unit Testing]如何存根有问题的代码 [单元测试]
【发布时间】:2017-04-21 21:11:03
【问题描述】:

编写单元测试的新手和更准确的“模拟”概念。我有一个基本函数“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)

【问题讨论】:

    标签: javascript unit-testing mocking sinon qunit


    【解决方案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 对象,而第二个是我想要“存根”的函数?
    • 是的,它通过 sinon.stub(object, "method") 作为参数。 Sinon 文档中有更多关于如何使用 stub 的详细信息。
    • 谢谢,但我发现他们的文档非常难以理解,因为有些人只是学习模拟、存根、间谍......
    【解决方案2】:

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

    您要使用的方法是在一个名为“learningCurve”的对象内,该对象位于“控制”对象内。

    如果控制在你的格式化程序中,你不能这样做吗:

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

    如果它不在格式化程序中,则可以创建一个新的控件实例并替换上面的内容。

    【讨论】:

      【解决方案3】:

      我发现单元测试的主要附加价值之一是它让你意识到你的代码可以在哪里重构。在您的情况下,有两个不同的问题:附加 % 和修改 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 框架进行单元测试。

      【讨论】:

        猜你喜欢
        • 2010-12-04
        • 2013-04-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-11-12
        • 2010-11-19
        • 1970-01-01
        相关资源
        最近更新 更多