Имитация перегруженных методов TS с помощью Jest сама по себе не сложна, но вы должны знать, как это сделать.

В этой статье я объясню «проблему» и как ее обойти.

Проблема"

Перегрузка методов — очень знакомая концепция для любого разработчика, привыкшего к объектно-ориентированному программированию (кстати, одна из многих, которые я объясню в своей будущей книге).

С помощью перегрузки методов вы можете определить несколько методов/функций с одинаковыми именами, но с разными сигнатурами. Перегрузку удобно использовать, поскольку конкретная реализация вызывается в зависимости от параметров, которые вы передаете.

Конечно, перегрузка методов — полезная концепция, а не проблема сама по себе. Однако во время тестирования может оказаться немного сложно имитировать перегруженные методы с помощью TypeScript.

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

Поначалу это может немного сбивать с толку.

Тогда, конечно, возникает проблема: как сообщить TypeScript, что мы хотим имитировать ту или иную версию функции?

Пример

Вот пример, показывающий проблему.

В моем текущем проекте я использую библиотеку nano для подключения к базе данных CouchDB. В частности, я использую nano в так называемых классах репозитория, которые отвечают за взаимодействие с базой данных.

При написании модульных тестов для новой операции «массового удаления» нам нужно было убедиться, что массовое удаление делает то, что нужно. Поскольку мы говорим о модульных тестах, мы действительно хотели сымитировать соединение с базой данных nano, а также вызов базы данных массовой операции.

С nano, когда мы устанавливаем соединение с базой данных, мы возвращаем объект типа DocumentScope<D>. Среди многих других функций интерфейс включает функцию bulk, которую можно использовать для выполнения массовых операций.

Эта функция на самом деле существует в двух вариантах:

Как видите, в зависимости от того, как он вызывается, мы возвращаем Promise<DocumentBulkResponse[]> или Promise<DocumentInsertResponse[]>;.

Второй вариант соответствует операции массовой вставки, а первый (тот, который нам нужно было смоделировать) — массовому удалению.

Обычно, когда мы имитируем функции с помощью Jest, мы делаем это следующим образом:

Это хорошо работает для случаев, когда есть один вариант, но в нашем случае нам нужно указать TypeScript, какой вариант мы имитируем; в противном случае мы получим ошибку компиляции, которая поначалу может ввести в заблуждение:

Теперь, когда вы знаете о двух вариантах функции, вы можете понять, откуда берется эта ошибка; TypeScript ожидает, что мы будем соблюдать сигнатуру (и, следовательно, также возвращаемый тип) второго варианта.

Мех!

Итак, как нам обойти эту проблему?

Решение

Решение этой проблемы с тестированием на самом деле довольно простое:

  • Определите настраиваемый тип, соответствующий сигнатуре варианта, который вы хотите имитировать.
  • Приведите тип, чтобы использовать тот, который вы только что определили перед созданием макета.

Вот пример:

С этим TypeScript больше не жалуется. Конечно, это всего лишь обходной путь, который иногда может вызывать проблемы (например, если изменяются сигнатуры фиктивных функций), но это полезный прием для продвижения вперед в тестировании.

Использованная литература:

Вывод

В этой статье я объяснил, как бороться с перегрузками при имитации функций с помощью Jest и TypeScript.

Есть и другие способы справиться с этим, но этот подход довольно прост (хотя и «слабый»). Официальная рекомендация команды TS заключается в том, что более общие перегрузки должны определяться последними, но некоторые библиотеки не всегда соблюдают это (в основном потому, что это не так хорошо известно, я думаю).

Вот и все на сегодня!

PS: Если вы хотите узнать массу других интересных вещей о программном обеспечении/веб-разработке, вы можете предварительно заказать мою будущую книгу, получить копию моей книги по TypeScript и/или подписаться на мой информационный бюллетень!