Обещания часто могут вызывать затруднения при проверке из-за их асинхронной природы. Изучив документацию Jasmine, вы можете подумать, что должен быть более простой способ проверки обещаний, чем использование setTimeout. Этот пост покажет вам простой подход к тестированию службы JavaScript с помощью экспортированной функции, которая возвращает обещание.

Модульное тестирование - это все о том, чтобы изолировать метод, который вы хотите протестировать, и посмотреть, как он себя ведет, когда принимает некоторые параметры или выполняет другие вызовы функций. Методы обычно зависят от других методов, и вы можете попасть в ситуацию, когда вы тестируете различные вызовы функций внутри этого одного метода. Это нарушает инкапсуляцию, и этого следует по возможности избегать. Для любой одной функции все, что вы хотите определить, - это то, возвращает ли функция ожидаемый результат при заданном наборе входных данных и обрабатывает ли она ошибки, если предоставлен недопустимый ввод.

В этом примере мы хотим протестировать открытую функцию fetchPlaylistsData в playlistsService.js.

Как видите, функция fetchPlaylistsData выполняет вызов функции из другой службы. Вот здесь и пригодится макет. Мок - это, по сути, фальшивый объект или тестовые данные, которые заменяют реальный объект, чтобы запускать примеры в соответствии со спецификацией. В Jasmine моки называются шпионами, которые позволяют получить определенную информацию о шпионской функции, например:

  1. Аргументы, переданные функции
  2. Какое значение возвращает функция
  3. Сколько раз вызывалась шпионская функция

В нашем модульном тесте мы хотим проверить, вызывает ли функция fetchPlaylistsData fetchData из apiService. Прежде чем мы начнем писать спецификацию, мы создаем фиктивный объект, представляющий структуру данных, которая должна быть возвращена из обещания.

Нам требуется это в верхней части нашего файла спецификации:

const promisedData = require('./promisedData.json');

Мы собираемся использовать объект promisedData вместе с spyOn. Мы собираемся передать spyOn службу и имя метода той службы, за которой мы хотим шпионить. Поскольку мы выполняем асинхронную операцию, мы должны возвращать обещание из этой функции. Если связать шпиона с and.returnValue, все вызовы функции вернут заданное конкретное значение. Мы предоставляем ему поддельный ответ, чтобы завершить вызов функции самостоятельно. Поскольку исходная функция возвращает обещание, фальшивый возврат также является обещанием: Promise.resolve(promisedData).

spyOn(apiService, 'fetchData').and.returnValue(Promise.resolve(promisedData));

Установив шпион на место, вы можете протестировать полный поток работы функции fetchPlaylistsData, зависящей от apiService.fetchData, не полагаясь на фактические ответы API. Важно отметить, что мы хотим тестировать playlistsService.fetchPlaylistsData, а не apiService.fetchData.

apiService.fetchData по сути является скрытым вводом для playlistsService.fetchPlaylistsData, поэтому мы подделываем его, как и другие вводы для playlistsService.fetchPlaylistsData вызова функции. Мы не хотим тестировать ответы API, потому что они являются внешними по отношению к нашему приложению.

Вы можете проверить шпионскую функцию в .then асинхронного вызова. Здесь вы можете использовать toHaveBeenCalled или toHaveBeenCalledWith, чтобы узнать, был ли он вызван. Вы также должны проверить, является ли результат обещания ожидаемым выводом, который вы хотите увидеть с помощью сопоставителя toEqual.

expect(apiService.fetchData).toHaveBeenCalledWith(video);
expect(result).toEqual(promisedData);

Поскольку мы тестируем асинхронный вызов, в вашем блоке beforeEach или it не забудьте позвонить done. Средство выполнения тестов будет ждать вызова функции done(), прежде чем перейти к следующему тесту.

Вы можете сделать со шпионами больше, например связать их с and.callThrough и and.callFake при проверке обещаний, но по большей части это все!

У вас есть работающий, проверенный JS-сервис! 🎉

Подробнее: