2009-11-26 82 views
4

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

目前我有两个场景在我的代码:

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

和:

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

我试着写了第一个场景一个单元测试,但我无法得到它运行到document.ready函数。至于第二种情况,我还没有想出一种方法来测试它(我无法提出一种测试方法和语法)。

因此,假设我无法更改源代码,是否有任何方法来测试这些功能? (假设测试它们是个好主意)

谢谢。

+0

你想要测试什么?只需测试代码,为什么你不应该测试你的代码在做什么? – powtac 2009-11-26 00:37:17

+0

我试图测试$(document).ready(function(){//测试这些代码});内部的逻辑。我正在使用JsTestDriver来测试我的JavaScript。目前,我无法访问document.ready块。 – BeraCim 2009-11-30 05:59:25

回答

6

您不需要测试$(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.") 
}); 
+1

@Igor:对于你的例子,如果有一堆不调用外部函数的逻辑(比如myInit)呢?我试图编写单元测试来测试myFunction,但我无法进入document.ready(语法明智)。有很多$(document).ready(function(){});在我的代码中,因此我觉得需要测试它们。然后我被告知不能令人信服地说,我不需要测试document.ready。因此我感到困惑。谢谢。 – BeraCim 2009-11-26 00:51:33

+0

@BeraCim要使用此解决方案,您可以将这些匿名函数重构为已命名的函数,以便您可以从单元测试访问它们,但这违反了您的问题中的某个约束(“假设我无法更改源代码”)。 – apollodude217 2011-05-31 20:50:59

0

该注册上准备处理程序应注册另一个函数,而不是一个匿名代码块的功能。然后,您可以测试调用$ .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时,您需要知道在调用这些回调函数时,“this”值不会由jQuery设置。在测试中,这会因为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() { 
} 
+0

因此除了将代码提取到单独的函数之外,没有办法测试匿名代码块吗? – BeraCim 2009-11-30 06:02:27

+0

您可以使用JSMock和Stub()函数来记录传入的回调,然后从相同的测试中调用该回调。这不是所希望的,因为现在你有一个测试验证单独的东西(导致不良缺陷本地化http://xunitpatterns.com/Goals%20of%20Test%20Automation.html#Defect%20Localization) – 2009-11-30 17:25:36