如何使用Jasmine测试JQuery插件?

时间:2011-11-23 00:32:36

标签: jquery jasmine

使用Jasmine对JQuery代码进行单元测试的最佳方法是什么?

我有这个简单的jQuery测试应用程序:

<div id='log'>log goes here</div>
<button id='btnClearLog'>Clear log</button>
<button id='btnAddLog'>Add log</button>

<script>
$(document).ready(function () {

    $('#log').empty(); 

    $('#btnClearLog').click(function () {
        $('#log').empty();  
    }); 

    $('#btnAddLog').click(function() {
        $('#log').append("<br />something");    
    }); 
});
</script>

这可以正常工作 - 文档加载时div #log为空,单击时添加到#log并清除#log。

但我不认为可以对此进行单元测试,因为JQuery代码在HTML页面内。

所以,我重写了这样的话:

<div id='log'>log goes here</div>
<button id='btnClearLog'>Clear log</button>
<button id='btnAddLog'>Add log</button>

<script>
$(document).ready(function () {

    $('#log').tester(); 

});
</script> 

并将JQuery代码外部化为一个单独的文件 - 就像这样 - 基于http://starter.pixelgraphics.us/生成的jQuery插件代码

(function($){

    $.Tester = function(el){

    var base = this;

            base.init = function(){

        $('#log').empty();

        $('#btnClearLog').click(function() {
            base.clear();
        });

        $('#btnAddLog').click(function() {
            base.add();
        });
            };

    base.clear = function(){
        $('#log').empty();
            };

    base.add = function(){
        $('#log').append("<br />something"); 
            };

            base.init();
    };

    $.fn.tester = function(){
        return this.each(function(){
            (new $.Tester(this));
        });
    };

})(jQuery);

这也可以按预期工作。

但是,我对Jasmine脚本的尝试不起作用。

describe('tester', function() { 

    it('log should be empty', function() { 
        var log = "<div id='log'>log</div>";
        var result = $(log).tester();
        expect(result).toBeEmpty();
    }

});

我尝试了上述的各种排列 - 都失败了:

"Expected '<div id="log">log</div>' to be empty"

是否可以测试以这种方式编写的插件?

以另一种方式编写代码以使其更易于测试是否更好?

1 个答案:

答案 0 :(得分:0)

这里有一些问题。首先,您将测试代码与查询代码的测试功能混合在一起。所以expect(result).toBeEmpty();将测试这个$('#log').empty()代码被调用,这是正确的测试,但它也测试该元素是空的,这不是你的工作。

其次,您在要测试的代码中创建新实例,使测试变得困难,导致您处理$。毕竟,最好只测试你的Tester()函数并将所有元素插入其中:

(function($){

    $.Tester = function(el, log, btnClearLog, btnAddLog){

    var base = this;

            base.init = function(){

        log.empty();

        btnClearLog.click(function() {
            base.clear();
        });

        btnAddLog.click(function() {
            base.add();
        });
            };

    base.clear = function(){
        log.empty();
            };

    base.add = function(){
        log.append("<br />something"); 
            };

            base.init();
    };

    $.fn.tester = function(){
        return this.each(function(){
            (new $.Tester(this, $('#log'), $('#btnClearLog'), $('#btnAddLog')));
        });
    };

})(jQuery);

这样做你只能测试你的Tester,传入一些模拟而不是真正的DOM元素。看看sinon如何创建和使用模拟。因为我们在JavaScript世界中你也可以模拟JQuery,只是不要将jquery插入你的测试端,而是通过模拟替换它。