Функция, которая регистрирует обработчик готовности, должна зарегистрировать другую функцию, а не анонимный кодовый блок. Затем вы можете протестировать код, который вызывает $ .ready (), отдельно от кода, который выполняется на ready. Итак, у вас есть:
- Один тест для проверки правильности функции установлен в качестве обработчика готовности
- Еще один тест для проверки того, что готовый обработчик делает правильные вещи
Чтобы протестировать сценарий 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() {
}