У меня есть функция, которая имеет 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:

  1. Все аргументы, переданные в функцию, превращаются в массив, а функция обратного вызова создается и добавляется к списку аргументов.
  2. Затем исходная асинхронная функция вызывается с новым списком аргументов с добавленным обратным вызовом.
  3. Когда функция завершит выполнение, она вызовет функцию обратного вызова, которая сама разрешит промис, внутри которого она вложена.

Когда я решил внести свой вклад в filer, я создал тест, чтобы увидеть, возвращается ли новый объект Promise через один из методов fsPromises после создания для него проблемы. Я решил не добавлять тесты, связанные с существующей реализацией метода fs, для их соответствующих версий, возвращающих промисы. Я чувствовал, что это может быть излишним, так как и стандартная, и обещанная версии методов filer, по-видимому, используют одну и ту же логику в файле implementation.js. И, судя по моему исследованию promisify, метод, используемый filer для преобразования асинхронных методов в методы, возвращающие промисы, похоже, также не вносит изменений в логику. Однако я не на 100% уверен в этом утверждении, поскольку контекст методов обещаний, похоже, изменен в interface.js, так что, возможно, что-то подобное может оказать влияние, даже если сама логика не изменится.

Мой тест был простым, и реализация для него проста. Были разные способы, которыми я мог бы подойти к этому тесту, и сначала я думал, что может потребоваться некоторая работа, чтобы создать его (или, по крайней мере, найти лучший способ сделать это). Однако я обнаружил, что chai уже предоставляет средства для тестирования объекта-обещания, и уже одно это упростило выполнение задачи.

Я создал свой pull request. Через некоторое время кто-то был достаточно любезен, чтобы предложить лучшее имя для одной из моих переменных. Я полностью с ними согласился, поскольку их предложение сделало наименования более точными/ясными и включило это исправление.

Изучая некоторые из существующих запросов на вытягивание, я понял, что другой пользователь допустил ошибку, которую сделал я, и добавил изменения в свой package-lock.json file.. к моим коммитам. Этот пользователь, вероятно, сделал то же самое, и я решил помочь им, поделившись с ними собственным решением проблемы.

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