【问题标题】:Unit testing jQuery document.ready function单元测试 jQuery document.ready 函数
【发布时间】:2009-11-26 00:07:24
【问题描述】:

我有一个关于单元测试 jQuery 的 document.ready function() 的问题。

目前我的代码中有 2 个场景:

function myFunction()
{
    $(document).ready(function() { ... });
}

还有:

$(document).ready(function()
{
    // some really long setup code here
});

我尝试为第一个场景编写单元测试,但我无法让它运行到 document.ready 函数中。至于第二种情况,我还没有想出测试它的方法(我无法想出测试它的方法和语法)。

所以假设我无法更改源代码,有什么方法可以测试这些功能吗? (假设测试它们是个好主意)

谢谢。

【问题讨论】:

  • 您到底想测试什么?只测试代码为什么不测试代码在做什么?
  • 我正在尝试测试 $(document).ready(function() { //test these code }); 中的逻辑。我正在使用 JsTestDriver 来测试我的 javascript。目前我很难进入 document.ready 块。

标签: javascript jquery unit-testing


【解决方案1】:

您不需要测试$(document).ready,因为它是框架的一部分并且已经过单元测试。在编写单元测试时,您需要测试两件事:

  1. 您与框架的交互。这包括确保您使用正确的参数调用正确的函数。
  2. 您自己的代码 - 您的代码做正确的事。

所以你真正需要做的是确保从$(document).ready 调用的任何代码都是正确的。

function myInit(){
//...
}
function myFunction()
{
  $(document).ready(myInit);
}

您现在需要做的就是对myInit 函数进行单元测试。

您还可以模拟 $.ready 函数以确保您正在调用它:

var readyCalled = false;
$.ready = function(func){
  readyCalled = (myInit == func);
}

//Your code containing `myInit` will get executed somewhere here
//....
//Then test:
test("Should have called ready", function() {
 ok(readyCalled, "ready should have been called with myInit as a parameter.")
});

【讨论】:

  • @Igor:对于您的示例,如果有一堆逻辑不调用外部函数(如 myInit)怎么办?我尝试编写单元测试来测试 myFunction,但我无法进入 document.ready(语法方面)。有很多 $(document).ready(function() {});在我的代码中,因此我觉得有必要测试它们。然后我被令人难以置信地告知我不需要测试 document.ready。因此我很困惑。谢谢。
  • @BeraCim 要使用此解决方案,您可以将这些匿名函数重构为命名函数,以便您可以从单元测试中访问它们,除非这违反了您问题中的一个约束(“假设我无法更改源代码”)。
【解决方案2】:

注册准备就绪处理程序的函数应该注册另一个函数,而不是匿名代码块。然后,您可以将调用 $.ready() 的代码与运行就绪的代码分开测试。所以你有:

  1. 验证正确函数的测试设置为就绪处理程序
  2. 另一个测试来验证准备好的处理程序是否正确

要测试场景 1,您需要为 jQuery 注入一个测试替身。这很困难,就像您重新定义 $ 或 jQuery 一样,您很可能会搞砸依赖它进行其他处理的其他代码(例如测试运行程序)。同时,您的代码可能仍希望在使用数组连接等实用方法时直接调用 jQuery。不过,任何控制反转模式都应该解决这个问题 (http://martinfowler.com/articles/injection.html)。

无论如何,这里有一些使用构造函数注入的代码(使用 JSMock 作为模拟库,使用 QUnit(jQuery 的)作为测试运行器):

// the code

var createComponent = function(_$) {
    var that = {};

    that.OnStart = function() {
        _$.ready(this.OnReady);
    };

    that.OnReady = function() {
    };

    return that;
};

// the test

test("OnStart associates the ready handler", function() {

   var sut;

   var mock$ = mc.createMock($);
   mock$.expects().ready(isA.TypeOf(Function)).andStub(function(callback) {
        equals(callback, sut.OnReady);
   });

   sut = createComponent(mock$);

   sut.OnStart();

   mc.verify();
});

test("OnReady does the right stuff", function() {
    //etc
});

我对 JS 中的所有事件处理程序都使用这种通用模式...您可能更喜欢使用原型类型类。当您将函数作为参数传递给 jQuery 时,您需要注意在调用这些回调时 jQuery 不会设置“this”值。在测试中,这会中断,因为 equals(callback, sut.OnReady) 不再通过。为了解决这个问题,您需要让事件处理程序直接成为每个实例的成员。你可以想象当有很多的时候有一个工具来获取它们的列表是很好的,但这表明让'OnReady'成为一个不依赖'this'的成员。

var Component = function(_$) {
    this._$ = _$;

    // repeat for each event handler thats tested
    this.OnReady = function() {
        Component.prototype.OnReady.apply(this);
    }
}

Component.prototype.Start = function() {
    this._$.ready(this.OnReady);
}

Component.prototype.OnReady = function() {
}

【讨论】:

  • 那么除了将代码取出到单独的函数中之外,没有办法测试匿名代码块吗?
  • 您可以使用 JSMock 的 andStub() 功能来记录传入的回调,然后从同一个测试中调用该回调。但这并不可取,因为现在您有一个测试来验证不同的东西(导致缺陷定位不佳xunitpatterns.com/…
【解决方案3】:

有关此问题的答案,请参阅帖子 herehere

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-23
    • 2011-08-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多