У меня есть функция, которая имеет 100% тестовое покрытие. Если я создам новую функцию из этой, используя метод promisify
из es6-promisify
, и решу написать тесты для новой функции, что насчет новой функции, которую я должен протестировать? Новая функция была изменена, чтобы возвращать промис, но как изменилась ее логика?
Этот вопрос беспокоил меня. Когда я спросил об этом, у меня не было интуитивного понимания того, как работают промисы, только поверхностное и базовое.
Поэтому, когда я решил внести свой вклад в Filer, написав модульный тест для метода в рамках его нового API, основанного на промисах, я был немного озадачен. Одно дело просто проверить вывод метода, но меня беспокоило, что и почему мой тест. Что именно я тестировал?
В Filer его методы превращаются в промисы через:
FileSystem.prototype.promises[methodName] = promisify(FileSystem.prototype[methodName].bind(fs));
Из того, что я мог сказать, если бы была добавлена какая-то новая логика к самим методам промисов, это было бы сделано там. Но при ближайшем рассмотрении я понял, что фактическое преобразование обрабатывается методом promisify
, методом, реализованным в зависимости с именем es6-promisify
.
Я понял, что технически тестирую результат функции promisify
, и поэтому решил взглянуть на исходный код для нее, чтобы увидеть, какие изменения могли быть внесены в ее ввод. Это на удивление небольшой проект, и код, выполнявший преобразование, был следующим:
Здесь мы возвращаем новую функцию, которая при вызове возвращает обещание. Если не предоставлена пользовательская реализация объекта Promise, будет возвращено обещание ES6 по умолчанию.
Эта функция показалась мне немного странной, она делала некоторые вещи, которых я раньше не замечал. Чтобы лучше понять это, я решил использовать promisify
в моей существующей программе, а затем вывести на консоль через различные промежутки времени выполнения функции.
node commands/quicknote.js the promisified function is running the original function is about to be called the callback function is running the promise has been returned
Из распечатки я собирался сделать вывод, что когда вызывается функция, созданная с помощью promisify
:
- Все аргументы, переданные в функцию, превращаются в массив, а функция обратного вызова создается и добавляется к списку аргументов.
- Затем исходная асинхронная функция вызывается с новым списком аргументов с добавленным обратным вызовом.
- Когда функция завершит выполнение, она вызовет функцию обратного вызова, которая сама разрешит промис, внутри которого она вложена.
Когда я решил внести свой вклад в filer, я создал тест, чтобы увидеть, возвращается ли новый объект Promise через один из методов fsPromises после создания для него проблемы. Я решил не добавлять тесты, связанные с существующей реализацией метода fs, для их соответствующих версий, возвращающих промисы. Я чувствовал, что это может быть излишним, так как и стандартная, и обещанная версии методов filer, по-видимому, используют одну и ту же логику в файле implementation.js. И, судя по моему исследованию promisify
, метод, используемый filer для преобразования асинхронных методов в методы, возвращающие промисы, похоже, также не вносит изменений в логику. Однако я не на 100% уверен в этом утверждении, поскольку контекст методов обещаний, похоже, изменен в interface.js, так что, возможно, что-то подобное может оказать влияние, даже если сама логика не изменится.
Мой тест был простым, и реализация для него проста. Были разные способы, которыми я мог бы подойти к этому тесту, и сначала я думал, что может потребоваться некоторая работа, чтобы создать его (или, по крайней мере, найти лучший способ сделать это). Однако я обнаружил, что chai уже предоставляет средства для тестирования объекта-обещания, и уже одно это упростило выполнение задачи.
Я создал свой pull request. Через некоторое время кто-то был достаточно любезен, чтобы предложить лучшее имя для одной из моих переменных. Я полностью с ними согласился, поскольку их предложение сделало наименования более точными/ясными и включило это исправление.
Изучая некоторые из существующих запросов на вытягивание, я понял, что другой пользователь допустил ошибку, которую сделал я, и добавил изменения в свой package-lock.json file.
. к моим коммитам. Этот пользователь, вероятно, сделал то же самое, и я решил помочь им, поделившись с ними собственным решением проблемы.
Это упражнение заняло больше времени, чем я ожидал, так как я уже был знаком с git. В базе кода было много новых концепций, к которым мне нужно было привыкнуть, и даже простое добавление простого теста требовало некоторого чтения и исследования с моей стороны. Но мне было весело, и в процессе я изучил несколько полезных приемов кодирования. Моя погоня за пресловутой кроличьей норой заставила меня понять, как много может уместиться в одной строке кода, если предположить, что она использует что-то из существующего проекта. Я всегда знал, что использование существующего кода может значительно упростить вещи, но на самом деле просмотр зависимостей делает реальность этой концепции намного более реальной.