1

用 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"

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

以另一种方式编写代码以使其更具可测试性会更好吗?

4

1 回答 1

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

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

于 2011-12-24T20:53:53.057 回答