Обещания часто могут вызывать затруднения при проверке из-за их асинхронной природы. Изучив документацию Jasmine, вы можете подумать, что должен быть более простой способ проверки обещаний, чем использование setTimeout
. Этот пост покажет вам простой подход к тестированию службы JavaScript с помощью экспортированной функции, которая возвращает обещание.
Модульное тестирование - это все о том, чтобы изолировать метод, который вы хотите протестировать, и посмотреть, как он себя ведет, когда принимает некоторые параметры или выполняет другие вызовы функций. Методы обычно зависят от других методов, и вы можете попасть в ситуацию, когда вы тестируете различные вызовы функций внутри этого одного метода. Это нарушает инкапсуляцию, и этого следует по возможности избегать. Для любой одной функции все, что вы хотите определить, - это то, возвращает ли функция ожидаемый результат при заданном наборе входных данных и обрабатывает ли она ошибки, если предоставлен недопустимый ввод.
В этом примере мы хотим протестировать открытую функцию fetchPlaylistsData
в playlistsService.js
.
Как видите, функция fetchPlaylistsData
выполняет вызов функции из другой службы. Вот здесь и пригодится макет. Мок - это, по сути, фальшивый объект или тестовые данные, которые заменяют реальный объект, чтобы запускать примеры в соответствии со спецификацией. В Jasmine моки называются шпионами, которые позволяют получить определенную информацию о шпионской функции, например:
- Аргументы, переданные функции
- Какое значение возвращает функция
- Сколько раз вызывалась шпионская функция
В нашем модульном тесте мы хотим проверить, вызывает ли функция 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-сервис! 🎉
Подробнее: