如何对输入框的事件监听器进行单元测试?

5
在最简单的测试中,我正在尝试测试以下函数:
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”键触发“submit”事件时,将调用“addPercentSign”函数。
我知道,单元测试的想法是尽可能地使测试与任何依赖项隔离开来。因此,要针对DOM操作进行测试,可以将元素附加到test.html的div下面,如下所示:
$('<input id="learningCurveInput" type="text"/>').appendTo('#qunit-fixture');

有人能解释一下接下来该怎么做吗?这个函数依赖于传递进来的Event对象来获取输入值。我不确定如何在测试中重新创建它。我附上了我的单元测试,但只是为了展示我的想法:

...,
    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”函数进行单元测试?

1个回答

11

我建议将其分为以下几个部分:

  • 测试从输入到输出的转换,例如:"51" -> "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() 这样的方法的测试:请检查它们的公共代码库以查看这些方法的覆盖范围。如果您正在实现自定义方法与 DOM 进行交互,则需要对它们进行测试。

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


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