33

How do you go about unit testing javascript that uses and modifies the DOM?

I'll give an easy example. A form validator that checks for blank text fields, written in javascript and that uses JQuery.

      function Validator() {

        this.isBlank = function(id) {
            if ($(id).val() == '') {
                return true;
            } else {
                return false;
          }
        };

        this.validate = function(inputs) {

           var errors = false;

           for (var field in inputs) {
               if (this.isBlank(inputs[field])) {
                   errors = true;
                   break;
               }
           }

           return errors;
       };
    }

Usage:

var validator = new Validator();
var fields = { field_1 : '#username', field_2 : '#email' };

if (!validator.validate(fields)) {
    console.log('validation failed');
} else {
    console.log('validation passed');
}

What is the best practice for attempting to unit test something like this?

4

3 回答 3

22

理想情况下,您应该拆分代码。验证逻辑并不真正需要 DOM 访问,因此您可以将其放入它自己的函数中,并将处理 ID 的逻辑放入一个值中,然后将其验证为另一个值。

通过这样做,您可以更轻松地对验证逻辑进行单元测试,并在必要时使用 Joseph the Dreamer 建议的一些工具对整个事物进行功能测试。

于 2013-06-01T04:41:24.590 回答
10

您可以使用Qunit进行涉及 DOM 的单元测试。如果您希望它自动化,您可以将Gruntgrunt-contrib-qunit任务一起使用,该任务在名为PhantomJS的无头 WebKit 中启动您的页面。

于 2013-06-01T03:42:42.727 回答
9

在不太可能的情况下,当您的大多数 JavaScript 代码包含逻辑并依赖少量 jQuery 代码(或实时 DOM 元素)时,您可以重构代码以轻松替换对 DOM 的访问/使用 jQuery,并使用模拟实现编写测试:

 function Validator(){
    this.getElementValue = function(id){return $(id).val();}

    this.check_blank = function(id){
    if(this.getElementValue(id) == '') // replace direct call to jQuery mock-able call
       return false;
    else
       return true;
    }....
}

并在测试中提供模拟实现:

 test("Basic valid field", function() {
   var validation = new Validator();

   // replace element accessor with mock implementation:
   validation.getElementValue = function(id){
     equals(id, "#my_field"); // assert that ID is expected one
     return "7";
   }
   var form_fields = {field_1 : '#my_field'};

   ok(validation.validate(form_fields), "non-empty field should be valid");
 }
于 2013-06-01T04:16:55.250 回答