В процессе разработки часто возникает необходимость в том, чтобы тесты не зависели от внешних сервисов, API или сложных внутренних компонентов. Для этого используется подход, известный как mocking (мокинг). Он позволяет создавать подделки (mock-объекты) для сложных зависимостей, чтобы тестировать лишь саму логику компонента, а не его взаимодействие с внешними сервисами или базой данных. В Jasmine mocking является важной частью создания изолированных и эффективных юнит-тестов.
В Jasmine для мокинга часто используется несколько встроенных
механизмов, таких как spyOn и создание кастомных объектов с
поведением, которое нужно для теста.
spyOn для мокинга
функцийМетод spyOn позволяет отслеживать вызовы методов
объектов и функций. Это полезно, когда необходимо проверить, был ли
вызван тот или иной метод, и с какими параметрами.
Пример использования spyOn:
describe('Тестирование метода с мокингом', function() {
it('должен вызывать метод calculate один раз', function() {
const calculator = {
calculate: function(a, b) { return a + b; }
};
spyOn(calculator, 'calculate');
calculator.calculate(2, 3);
expect(calculator.calculate).toHaveBeenCalled();
expect(calculator.calculate).toHaveBeenCalledWith(2, 3);
});
});
В этом примере spyOn следит за методом
calculate. После вызова метода проверяется, что он был
вызван, а также с ожидаемыми аргументами.
and.returnValueВ случае, если необходимо, чтобы мок-функция возвращала определённое
значение, можно использовать метод and.returnValue. Это
позволяет задать поведение мокированной функции.
Пример:
describe('Тестирование с мокированием значения', function() {
it('должен возвращать заданное значение', function() {
const apiService = {
fetchData: function() { return 'реальные данные'; }
};
spyOn(apiService, 'fetchData').and.returnValue('мокированные данные');
const result = apiService.fetchData();
expect(result).toBe('мокированные данные');
});
});
Здесь мокируем метод fetchData и задаём ему возвращаемое
значение — мокированные данные.
and.callFake для создания кастомной логикиЕсли нужно, чтобы мок-функция выполняла кастомное поведение
(например, обработку аргументов или возвращение значений в зависимости
от условий), используется метод and.callFake.
Пример:
describe('Мокинг с кастомной логикой', function() {
it('должен корректно обработать аргументы', function() {
const apiService = {
fetchData: function(id) { return 'данные для ' + id; }
};
spyOn(apiService, 'fetchData').and.callFake(function(id) {
return 'мокированные данные для ' + id;
});
const result = apiService.fetchData(42);
expect(result).toBe('мокированные данные для 42');
});
});
Здесь с помощью callFake мы задаём свою логику
выполнения метода, которая возвращает значение в зависимости от
переданного аргумента.
Когда внешний сервис или компонент невозможно или нецелесообразно мокировать вручную, на помощь приходят специализированные библиотеки для мокинга. Одной из таких является Sinon.js. Она предоставляет более гибкие возможности для создания мока, стабов и шпионов, включая возможность работы с промисами и асинхронными операциями.
Пример использования Sinon для мокинга:
describe('Мокинг с Sinon', function() {
it('должен мокировать асинхронный запрос', function(done) {
const request = sinon.stub().returns(Promise.resolve('мокированные данные'));
request().then(function(result) {
expect(result).toBe('мокированные данные');
done();
});
});
});
Асинхронное тестирование требует особого подхода, так как часто нужно
ожидать завершения операций, таких как запросы к серверу. В Jasmine
можно комбинировать мокинг с асинхронными тестами, например, используя
done() для отслеживания завершения операции.
Пример асинхронного теста с мокированием:
describe('Тестирование асинхронных операций', function() {
it('должен вернуть мокированные данные после задержки', function(done) {
const fetchDataAsync = function() {
return new Promise((resolve) => {
setTimeout(() => resolve('мокированные данные'), 100);
});
};
spyOn(window, 'fetchDataAsync').and.callFake(fetchDataAsync);
fetchDataAsync().then((data) => {
expect(data).toBe('мокированные данные');
done();
});
});
});
Здесь мы мокируем функцию fetchDataAsync, которая
возвращает промис, и проверяем, что асинхронная операция завершится с
нужным результатом.
Mocking является неотъемлемой частью юнит-тестирования, позволяя создавать предсказуемые и надежные тесты, которые не зависят от внешних компонентов.