Mocking (или создание макетов) — это процесс замены реальных зависимостей или объектов в тестах на фиктивные версии, которые имитируют их поведение. Это важный аспект тестирования, так как позволяет быстрее и эффективнее проводить юнит-тесты, изолируя тестируемый код от внешних факторов, таких как базы данных, API или сторонние сервисы.
В Jasmine mocking используется для создания поддельных версий функций, объектов или методов, которые контролируют взаимодействие с внешними системами. Такой подход повышает скорость тестирования и дает возможность точнее изолировать тестируемый функционал.
Jasmine предоставляет несколько инструментов для работы с
mock-объектами, основными из которых являются функции
spyOn, mock и stub.
Метод spyOn используется для подмены функций или методов
в тестируемом объекте. Этот метод позволяет перехватывать вызовы и, при
необходимости, изменять поведение функции. Он не удаляет оригинальную
реализацию метода, а заменяет её временно на поддельную.
Пример использования:
describe('Тестирование функции с использованием spyOn', function() {
it('должен вызывать метод sendData', function() {
var service = {
sendData: function(data) {
return 'data sent';
}
};
// Создаём шпион на методе sendData
spyOn(service, 'sendData').and.callThrough();
service.sendData('test');
// Проверка, что метод был вызван
expect(service.sendData).toHaveBeenCalled();
});
});
В этом примере мы подменили метод sendData в объекте
service с помощью spyOn. Метод
callThrough() позволяет вызвать оригинальную реализацию
метода после перехвата. Также можно использовать
and.returnValue(value), чтобы задать конкретный результат
для метода.
Если нужно заменить возвращаемое значение без выполнения оригинальной
логики, можно использовать and.returnValue:
describe('Тестирование с возвращаемым значением', function() {
it('должен вернуть заглушенное значение', function() {
var service = {
getData: function() {
return 'real data';
}
};
spyOn(service, 'getData').and.returnValue('mock data');
expect(service.getData()).toBe('mock data');
});
});
Здесь метод getData всегда будет возвращать
'mock data', независимо от того, что происходит в
оригинальной реализации.
В отличие от шпионов, которые сохраняют оригинальную реализацию функции, заглушки позволяют полностью подменить метод, предоставляя контролируемое поведение. Это особенно полезно в ситуациях, когда необходимо заменить сложную логику, такую как запросы к внешним API.
Пример использования заглушки:
describe('Заглушка для асинхронного вызова', function() {
it('должен использовать mock для асинхронного метода', function(done) {
var service = {
fetchData: function(callback) {
setTimeout(function() {
callback('real data');
}, 1000);
}
};
spyOn(service, 'fetchData').and.callFake(function(callback) {
callback('mock data');
done();
});
service.fetchData(function(result) {
expect(result).toBe('mock data');
});
});
});
Здесь метод fetchData заменяется на поддельную версию с
помощью and.callFake, что позволяет нам точно
контролировать, что происходит внутри функции, и получить нужные
результаты.
Mocking также применим при тестировании классов и их методов. Рассмотрим пример, где класс взаимодействует с внешним API:
class ApiService {
fetchData() {
return fetch('https://api.example.com/data').then(response => response.json());
}
}
describe('Тестирование ApiService с использованием mock', function() {
it('должен использовать мок для fetch', function(done) {
var apiService = new ApiService();
spyOn(window, 'fetch').and.returnValue(Promise.resolve({
json: function() {
return Promise.resolve({ message: 'mock data' });
}
}));
apiService.fetchData().then(function(data) {
expect(data.message).toBe('mock data');
done();
});
});
});
Здесь метод fetch глобального объекта
window заменён на поддельную версию, которая возвращает
заранее заданные данные. Это позволяет протестировать работу метода
fetchData без реального выполнения HTTP-запроса.
Восстановление оригинальных функций: После
использования spyOn, оригинальные функции можно
восстановить с помощью метода and.callThrough(), который
восстанавливает исходное поведение. Также можно использовать
mockRestore для восстановления состояния в более сложных
случаях.
Асинхронность: При тестировании асинхронных
функций важно корректно работать с done() для уведомления
Jasmine о завершении теста. Для промисов можно использовать
.then() для обработки результата.
Сложные зависимости: Если тестируемая функция
зависит от нескольких сложных объектов, можно использовать несколько
spyOn и заглушек для всех этих зависимостей. Однако следует
избегать слишком сложных mock-объектов, так как это может усложнить
поддержку тестов.
Гибкость: Jasmine предоставляет гибкие
инструменты для имитации поведения объектов и функций. Вместо того чтобы
создавать полноценные фиктивные объекты, можно использовать
and.callFake, чтобы точно контролировать поведение во время
тестов.
Mocking в Jasmine — мощный инструмент для ускорения и изоляции
тестов. Он позволяет эффективно заменить внешние зависимости, эмулируя
их поведение, что существенно повышает скорость выполнения тестов и
улучшает стабильность тестируемых систем. Основное внимание следует
уделить корректному использованию методов spyOn и
and.callFake, а также правильному управлению асинхронными
вызовами.