Асинхронные операции в Backbone.js чаще всего связаны с
взаимодействием с сервером через
Backbone.Model и
Backbone.Collection, использующих методы
fetch, save и destroy.
Тестирование таких операций требует внимания к синхронизации и
корректной обработке обратных вызовов (callbacks) или промисов.
1. Использование спаев и моков
Backbone.js предоставляет гибкость через возможность переопределения
метода sync, который отвечает за коммуникацию с сервером.
Для тестирования его обычно подменяют на мок-функцию.
describe('Model fetch', function() {
var model;
beforeEach(function() {
model = new Backbone.Model();
sinon.stub(model, 'sync').callsFake(function(method, model, options) {
options.success({id: 1, name: 'Test'});
});
});
it('должен обновлять атрибуты модели после fetch', function(done) {
model.fetch({
success: function() {
expect(model.get('id')).to.equal(1);
expect(model.get('name')).to.equal('Test');
done();
}
});
});
});
Ключевой момент: использование done в асинхронных тестах
позволяет тестовому раннеру дождаться завершения операции перед
проверкой утверждений.
2. Работа с промисами и fetch
Современные реализации Backbone позволяют использовать промисы для
обработки результатов асинхронных операций. В тестах можно использовать
async/await для упрощения кода.
it('fetch возвращает корректные данные', async function() {
var model = new Backbone.Model();
sinon.stub(model, 'sync').resolves({id: 42, title: 'Async Test'});
await model.fetch();
expect(model.get('id')).to.equal(42);
expect(model.get('title')).to.equal('Async Test');
});
Использование resolves из sinon позволяет
имитировать успешный ответ сервера без фактического сетевого
запроса.
Асинхронные операции могут завершаться с ошибкой. В Backbone.js для
этого используется обратный вызов error. В тестах
необходимо проверять корректную обработку этих ситуаций.
it('должен вызывать error при неудачном fetch', function(done) {
var model = new Backbone.Model();
sinon.stub(model, 'sync').callsFake(function(method, model, options) {
options.error(model, 'Server error');
});
model.fetch({
error: function(model, response) {
expect(response).to.equal('Server error');
done();
}
});
});
Особенность: важно убедиться, что тест не завершится раньше вызова
error. Для этого используется done или промисы.
Коллекции наследуют поведение моделей, поэтому методы
fetch, create и destroy также
могут быть протестированы через моки sync.
describe('Collection fetch', function() {
var collection;
beforeEach(function() {
collection = new Backbone.Collection();
sinon.stub(collection, 'sync').callsFake(function(method, model, options) {
options.success([{id: 1}, {id: 2}]);
});
});
it('должна заполняться моделями после fetch', function(done) {
collection.fetch({
success: function() {
expect(collection.length).to.equal(2);
expect(collection.at(0).get('id')).to.equal(1);
done();
}
});
});
});
Ключевое: проверка корректного заполнения коллекции после асинхронного запроса.
Для проверки работы с настоящим API удобно использовать тестовый
сервер, например через json-server или
express. В этом случае тесты могут быть асинхронными,
используя async/await.
it('fetch с реальным сервером', async function() {
var model = new Backbone.Model({id: 1});
await model.fetch({url: '/api/items/1'});
expect(model.get('id')).to.equal(1);
expect(model.get('name')).to.be.a('string');
});
Рекомендация: для интеграционных тестов желательно изолировать тестовую базу данных или использовать мок-сервер, чтобы избежать зависимости от внешнего состояния.
done или промисы для корректного
завершения асинхронных тестов.sinon.stub(model, 'sync') или специализированные библиотеки
(fetch-mock, nock).Асинхронное тестирование Backbone.js требует тщательного контроля за временем выполнения операций и предсказуемости данных. Использование моков и промисов обеспечивает стабильность тестовой среды и минимизирует зависимость от внешних сервисов.