注册 on ready 处理程序的函数应该注册另一个函数,而不是匿名代码块。这样,您就可以将调用 $.ready() 的代码与在 ready 上运行的代码分开测试。因此,您有:
1. 一个测试来验证正确的函数被设置为 ready 处理程序
2. 另一个测试来验证 ready 处理程序执行正确的操作
要测试方案 1,您需要为 jQuery 注入一个测试替身。这很困难,因为如果重新定义 $ 或 jQuery,很可能会破坏依赖它进行其他处理(如测试运行器)的其他代码。同时,当您使用实用方法(如数组连接)时,您的代码仍然可能希望直接调用 jQuery。不过,任何控制反转模式都应该解决这个问题(
http://martinfowler.com/articles/injection.html)。
无论如何,这里是一些使用构造函数注入的代码(使用 JSMock 作为模拟库,使用 QUnit(jQuery 的一部分)作为测试运行器):
var createComponent = function(_$) {
var that = {};
that.OnStart = function() {
_$.ready(this.OnReady);
};
that.OnReady = function() {
};
return that;
};
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() {
});
我在JS中使用这个通用模式来处理所有的事件处理程序... 你可能更喜欢使用原型类型类。当你将函数作为参数传递给jQuery时,需要注意的是,当调用这些回调函数时,jQuery不会设置"this"值。在测试中,这会导致equals(callback, sut.OnReady)不再通过。为了解决这个问题,你需要使事件处理程序成为每个实例的直接成员。你可以想象当有很多实例时,有一个工具可以接受它们的列表,但这演示了使"OnReady"成为一个不依赖于"this"的成员。
var Component = function(_$) {
this._$ = _$;
this.OnReady = function() {
Component.prototype.OnReady.apply(this);
}
}
Component.prototype.Start = function() {
this._$.ready(this.OnReady);
}
Component.prototype.OnReady = function() {
}