Возвращаемые значения через and.returnValue

В Jasmine существует мощный механизм шпионов (spies), позволяющий отслеживать вызовы функций и управлять их поведением. Одним из ключевых инструментов управления результатами вызова функции является метод and.returnValue. Он позволяет задать фиксированное значение, которое будет возвращаться при каждом вызове шпионской функции.

Основы использования and.returnValue

Метод применяется к шпиону следующим образом:

const calculator = {
  sum: (a, b) => a + b
};

spyOn(calculator, 'sum').and.returnValue(10);

const result = calculator.sum(3, 7);
console.log(result); // 10

В этом примере исходная реализация sum полностью игнорируется. Каждый вызов calculator.sum будет возвращать 10, независимо от переданных аргументов. Это позволяет:

  • Изолировать тестируемый код от внешних зависимостей.
  • Ускорить тесты, избегая сложных вычислений.
  • Создавать предсказуемое поведение для сценариев, где важен результат функции, а не её логика.

Отличие от callFake

and.returnValue возвращает фиксированное значение, тогда как and.callFake позволяет подменять функцию с произвольной логикой. Например:

spyOn(calculator, 'sum').and.callFake((a, b) => a * b);

console.log(calculator.sum(3, 4)); // 12

Если требуется лишь стабилизировать возвращаемое значение без написания новой логики, and.returnValue является более лаконичным и наглядным решением.

Применение с асинхронными функциями

and.returnValue работает только с синхронными значениями. Для имитации промисов или асинхронных результатов используется and.returnValue(Promise.resolve(value)):

const api = {
  fetchData: () => fetch('/data')
};

spyOn(api, 'fetchData').and.returnValue(Promise.resolve({ id: 1, name: 'Test' }));

api.fetchData().then(data => console.log(data)); // { id: 1, name: 'Test' }

Это позволяет полностью контролировать поведение асинхронных функций без необходимости обращаться к реальному серверу.

Взаимодействие с аргументами функции

Метод and.returnValue не учитывает аргументы вызова. Любое количество вызовов с любыми параметрами вернёт одно и то же значение. Если требуется возвращать разные значения в зависимости от аргументов, нужно использовать:

  • and.callFake с кастомной логикой
  • and.returnValues для последовательных значений

Пример с and.returnValues:

spyOn(calculator, 'sum').and.returnValues(1, 2, 3);

console.log(calculator.sum()); // 1
console.log(calculator.sum()); // 2
console.log(calculator.sum()); // 3
console.log(calculator.sum()); // undefined (после исчерпания списка)

Проверка вызова функции с and.returnValue

Метод and.returnValue хорошо сочетается с проверками вызова через toHaveBeenCalled и toHaveBeenCalledWith:

spyOn(calculator, 'sum').and.returnValue(5);

calculator.sum(2, 3);

expect(calculator.sum).toHaveBeenCalled();
expect(calculator.sum).toHaveBeenCalledWith(2, 3);
expect(calculator.sum()).toBe(5);

Это позволяет не только гарантировать возвращаемое значение, но и отслеживать корректность использования функции в тестируемом коде.

Ограничения и особенности

  • and.returnValue нельзя использовать для конструкторов или методов, которые должны создавать новые объекты с внутренним состоянием, так как возвращаемое значение будет одно и то же для всех вызовов.
  • Невозможно задать динамическое поведение в зависимости от аргументов. Для этого требуется callFake.
  • Для последовательных разных возвращаемых значений лучше использовать and.returnValues.

Практический пример

Предположим, есть модуль, который зависит от внешнего сервиса:

const weatherService = {
  getTemperature: city => {
    // Реальный вызов к API
  }
};

const weatherReporter = {
  report: city => `Температура в ${city} ${weatherService.getTemperature(city)}°C`
};

Тест с подменой значения:

spyOn(weatherService, 'getTemperature').and.returnValue(25);

expect(weatherReporter.report('Москва')).toBe('Температура в Москва 25°C');
expect(weatherService.getTemperature).toHaveBeenCalledWith('Москва');

Здесь тест полностью изолирован от внешнего API, а результат фиксирован, что делает проверку предсказуемой.

Заключение по использованию

Метод and.returnValue — это простой и эффективный инструмент для управления возвращаемыми значениями шпионских функций. Он позволяет создавать стабильные, изолированные тесты и минимизировать зависимости, сохраняя при этом ясность кода. Используется преимущественно для синхронных функций с фиксированным результатом, но может быть адаптирован для работы с промисами и последовательными значениями.