【问题标题】:How can I unit test an event listener on an input field?如何对输入字段的事件侦听器进行单元测试?
【发布时间】:2017-04-25 11:15:34
【问题描述】:

在最简单的测试中,我正在尝试测试以下功能:

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

            if (inputNumber) {

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

                    control.learningCurve.setValue(finalOutput);

                    return finalOutput;
                };
            }
        }

上述函数是输入字段 (id="learningCurveInput") 上的事件监听器。当用户在字段中输入一个值,然后触发一个“提交”事件(通过“ENTER”键),“addPercentSign”函数被调用。

我了解单元测试的想法是尽可能地将测试与任何依赖项“隔离”。因此,要针对 DOM 操作进行测试,可以将元素附加到 div 下的 test.html,如下所示:

$('<input id="learningCurveInput" type="text"/>').appendTo('#qunit-fixture');

谁能解释一下接下来要做什么?该函数依赖于传入的事件对象来检索输入值。我不确定如何在测试中重新创建它。我在下面附上了我的单元测试,但这只是为了展示我的想法:

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

        QUnit.module("Formatter Object Exists")

        QUnit.test("Learning Curve Input Value", function (assert) {

            $('<input id="learningCurveInput" type="text"/>').appendTo('#qunit-fixture');

            $("#learningCurveInput").val("55");

            var result = '55';

            equals(result, $('#learningCurveInput').val(), "testing input value"); 
        });

         QUnit.test("addPecentSign Function", function (assert) {
              //how to test this dom-dependent function?
        });

    }
);

问题总结

如何对输入字段的“提交”时调用的“addPercentSign”函数进行单元测试?

【问题讨论】:

    标签: javascript jquery unit-testing dom qunit


    【解决方案1】:

    我建议将其拆分为以下部分:

    • 测试输入到输出的转换,即:"51" -&gt; "51.0%"
    • 测试您修改input 值的方法是否有效
    • 测试您附加的事件侦听器是否在需要时被调用

    如果所有这些测试都成功,您可以假设将它们链接在一起也可以。

    为了测试转换方法,我建议将其逻辑移到一个单独的纯函数中。我在下面粘贴了您的格式逻辑并删除了 setValue 副作用。我包括了一些测试(您应该检查它们,看看您是否需要更多/它们是否符合您的要求)。我留下了两个失败的测试作为例子。

    字符串格式测试:

    function addPercentSign(val) {
      var inputNumber = parseFloat(val);
    
      if (inputNumber) {
        if (inputNumber < 50 || inputNumber > 100) {
          //see learningCurveFormatCheck
          return null;
        } else {
          var finalVal = inputNumber.toFixed(1);
          var finalOutput = finalVal + "%";
    
          return finalOutput;
        };
      };
    };
    
    module("String formatting");
    
    test("Returns undefined for unparseable strings", function() {
    	["foo", null, NaN, "0.0.0"]
        .forEach(function(result, i, arr) {
        	var result = addPercentSign(result);
        	strictEqual(result, undefined, arr[i] + " produces " + result);
        });
    });
    
    test("Returns null for values below 50 and above 100", function() {
    	["0", "0.0", "25", "49.99999", "100.00000001", "10300", Infinity]
      	.forEach(function(result, i, arr) {
        	var result = addPercentSign(result);
        	strictEqual(result, null, arr[i] + " produces " + result);
        });
    });
    
    test("Appends a % sign for values between 50 and 100", function() {
    	strictEqual(addPercentSign("51.0"), "51.0%");
    	// ...
    });
    
    test("Appends a digit for values without one", function() {
    	strictEqual(addPercentSign("51"), "51.0%");
    	// ...
    });
    
    test("Removes and rounds digits for values with more than one", function() {
    	strictEqual(addPercentSign("51.999"), "52.0%");
      	strictEqual(addPercentSign("51.06"), "51.1%");
    	// ...
    });
    <link href="https://code.jquery.com/qunit/qunit-1.12.0.css" rel="stylesheet"/>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <script src="https://code.jquery.com/qunit/qunit-1.12.0.js"></script>
    
    <div id="qunit"></div>
    <div id="qunit-fixture"></div>

    现在您已经掌握了这个方法,您需要确定是否可以从 检索值并将值写入 输入字段。这些和你已经写的很相似:

    获取和设置输入的value

    function createInput() {
      return $('<input id="learningCurveInput" type="text" value="hello world"/>')
        .appendTo('#qunit-fixture');
    }
    
    module("Writing and reading to input", {})
    
    test("writes to value", function(assert) {
      var $input = createInput();
      var result = "55";
    
      // Whatever you're using to set:
      // in your code, I read `control.learningCurve.setValue`
      // if that's what you're using, that's the method you should test
      $input.val(result);
    
      strictEqual($input.val(), result);
    });
    
    test("reads from value", function(assert) {
      var $input = createInput();
      
      // Whatever you're using to get the value
      $input.val();
    
      strictEqual($input.val(), "hello world");
    });
    <link href="https://code.jquery.com/qunit/qunit-1.12.0.css" rel="stylesheet"/>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <script src="https://code.jquery.com/qunit/qunit-1.12.0.js"></script>
    
    <div id="qunit"></div>
    <div id="qunit-fixture"></div>

    既然您知道您可以 (a) 正确地转换值,并且 (b) 正确地读取和写入值,您需要测试您的 获取值 -> 转换值 -> 设置值 序列将由正确的输入触发。例如:

    测试事件监听器

    jQuery 有一些方便的方法来附加和触发事件监听器。您可以使用不带参数的 .changesubmit 来模拟 UI 输入。或者,您可以在提交按钮上触发click

    function createForm() {
      return $("<form></form>")
        .append(createInput());
    }
    
    function createInput() {
      return $('<input id="learningCurveInput" type="text" value="hello world"/>')
        .appendTo('#qunit-fixture');
    }
    
    module("Form event listeners", {})
    
    test("input executes method on change", function(assert) {
      var called = false;
      var onChange = function() { called = true; };
      var $input = createInput();
      $input.change(onChange);
      
      $input.val("test");
      strictEqual(called, false);
      
      $input.change();
      strictEqual(called, true);
      
    });
    
    test("form executes method on submit", function(assert) {
      var called = false;
      var onSubmit = function() { called = true; };
      var $form = createForm();
      var $input = $form.find("input");
      
      $form.submit(onSubmit);
      
      strictEqual(called, false);
      
      $form.submit();
      strictEqual(called, true);
      
    });
    <link href="https://code.jquery.com/qunit/qunit-1.12.0.css" rel="stylesheet"/>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <script src="https://code.jquery.com/qunit/qunit-1.12.0.js"></script>
    
    <div id="qunit"></div>
    <div id="qunit-fixture"></div>

    结束

    现在,您可以确定您的代码的实现是否包含在您的测试中:

    $("form").submit(function() {                   // Tested in test 3
      var $input = $(this).find("input");
      var originalValue = $input.val();             // Tested in test 2
      var newValue = addPercentSign(originalValue); // Tested in test 1
      $input.val(newValue);                         // Tested in test 2
    });
    

    请注意,它主要是第一个具有自定义逻辑和要求的测试模块。如果您使用的是已经过大量测试的 jQuery,则无需为 .val() 等方法重新实现测试:查看他们的公共 repo 以查看这些方法的覆盖范围。如果您正在实现与 DOM 交互的自定义​​方法,您确实需要测试它们。

    因此,简而言之:将addPercentageSign 重写为接受字符串并返回字符串的纯函数;确保它经过彻底测试。通过经过测试的库与 DOM 交互,或者为 DOM 编辑和事件监听编写测试。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-07-17
      • 1970-01-01
      • 2019-01-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-05-23
      相关资源
      最近更新 更多