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

Это сообщение было рецензировано Кевином Хосфордом

TL; DR

тестовая среда jest, система внедрения зависимостей

Фреймворк шутливого тестирования имеет простой API имитации зависимостей, который использует модульную систему Node.js в качестве тестовой среды выполнения, системы внедрения зависимостей. Любые зависимости, импортированные в файл Javascript с помощью операторов require, могут иметь переопределенное поведение по умолчанию (Примечание: jest также можно настроить для правильного анализа синтаксиса модуля ES)

Поведение макета может быть активировано (отключено по умолчанию) для каждого тестового сценария. Например, тестовый сценарий user.spec.js может выбрать имитируемое поведение собственной fs библиотеки Node.js, в то время как account.spec.js может предпочесть использовать фактическую fs логику, предоставляемую собственной библиотекой Node.js. Стоит отметить, что jest не допускает одновременного использования обоих в одном тестовом сценарии: тестовый сценарий не может имитировать модуль для некоторых тестов, а затем вернуться к фактической логике зависимости для других тестов. На уровне тестового сценария это либо одно, либо другое.

Определение ручных макетов модулей Javascript

jest использует простое соглашение, чтобы найти определения поведения для ручных имитаций. Он ожидает, что файл JavaScript с тем же именем, что и зависимость, будет имитировать, расположенный в подкаталоге __mocks__ пути, на котором размещена указанная зависимость. Собственные библиотеки Node.js (например, fs) и зависимости, которые были npm installed, имеют несколько иное соглашение: файл определения макета должен называться так же, как строка, используемая в require (например, fs будет имитировать fs.js), расположенный в __mocks__ подкаталог в корневом каталоге проекта.

Рассмотрим экспорт authenticateUser из следующего модуля Node.js:

При написании модульных тестов для этого примера модуля, вероятно, захочется имитировать как импорт bcrypt, так и getHashedPasswordFromDB. bcrypt методы следует высмеивать, потому что для их выполнения может потребоваться время. getHashedPasswordFromDB методы должны быть имитирующими, чтобы избежать нежелательных запросов к базе данных. Кроме того, можно написать тесты, чтобы утверждать, что authenticateUser может обрабатывать случаи, когда bcrypt или getHashedPasswordFromDB выдают ошибки. Ручные имитации этих зависимостей позволяют детерминистически имитировать эти случаи ошибок.

В качестве примера давайте посмеемся над getHashedPasswordFromDB. Нам нужно будет создать фиктивный файл определения, связанный с ./models/user.js. Это будет /models/__mocks__/user.js:

Идея состоит в том, что открытый интерфейс моделируемой зависимости должен быть воссоздан с помощью альтернативных реализаций, которые имеют аналогичное поведение return. В этом случае наша тестируемая функция authenticateUser ожидает, что сможет импортировать функцию getHashedPasswordFromDB из ./models/user.js, которая возвращает Promise. Мы используем jest.fn() для создания Jest mock object, который будет использоваться в качестве экспорта. Поведение при возврате Promise можно эмулировать, передав анонимную функцию jest.fn(), которая определяет это поведение. Дополнительную информацию см. В следующем разделе.

Поведение, определенное в этих макетных сценариях, можно рассматривать как поведение макета по умолчанию. Часто это поведение по умолчанию необходимо переопределить в пользу более уникального поведения, специфичного для конкретных тестов. Мы немного рассмотрим это на примере.

Использование jest.fn() для создания имитационного поведения

Для имитируемой функции getHashedPasswordFromDB мы определили поведение по умолчанию как возвращение Promise, которое разрешается с пустым объектом. Определение сложных имитаций поведения становится тривиальным за счет использования jest метода тестовой фабрики шпиона объекта: fn.

Вызывается без каких-либо аргументов, jest.fn() возвращает базовый, «безоперационный» jest объект шпиона. Когда этот шпионский объект вызывается, он возвращает undefined (т.е. то же самое, что и вызов function () {}). Это может оказаться эффективным для предотвращения некоторых типов вызовов зависимостей от создания нежелательных побочных эффектов, например. предотвращение создания журналов при вызове методов библиотеки регистратора во время выполнения теста.

Если фабрике передается функция, возвращенный объект-шпион будет вести себя как переданная функция при вызове, например. когда возвращение

jest.fn(function increment(value) { return value + 1 })

вызывается, наблюдаемое поведение будет имитировать

function increment(value) { return value + 1 }

Тестовые шпионы, созданные с помощью jest.fn(), невероятно мощны. За подробностями обращайтесь к документации API шпионского теста шутки.

Использование ручного макета в тестовом наборе

Напишем тест, который утверждает:

›Если getHashedPasswordFromDB вызывает ошибку, authenticateUser возвращает Promise, который отклоняет с указанной ошибкой

Как написано, этот тест включает ручной имитатор модуля user.js (строка 5). Затем, в функции getHashedPasswordFromDB имитация имитационного поведения по умолчанию заменяется (строка 14) особым поведением, уникальным для этого теста: она выдает определенную ошибку. Это достигается с помощью mockImplementationOnce() метода тестового шпиона, который переопределяет поведение имита по умолчанию для одного вызова, а послесловия возвращаются к фиктивному поведению по умолчанию.

Если бы метод mockImplementationOnce() не был вызван в строке 14, в этом тесте использовалось бы поведение по умолчанию, определенное в ручном макете getHashedPasswordFromDB.

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