Это тривиальный пример, который иллюстрирует суть моей проблемы:
var innerLib = require('./path/to/innerLib');
function underTest() {
return innerLib.doComplexStuff();
}
module.exports = underTest;
Я пытаюсь написать модульный тест для этого кода. Как я могу смоделировать требование для innerLib
без макетирования require
функции полностью?
Так что это я пытаюсь смоделировать глобальное require
и выяснить, что это не сработает даже для этого:
var path = require('path'),
vm = require('vm'),
fs = require('fs'),
indexPath = path.join(__dirname, './underTest');
var globalRequire = require;
require = function(name) {
console.log('require: ' + name);
switch(name) {
case 'connect':
case indexPath:
return globalRequire(name);
break;
}
};
Проблема в том, что require
функция внутри underTest.js
файла фактически не была отключена. Это все еще указывает на глобальную require
функцию. Таким образом, кажется, что я могу смоделировать require
функцию только в том же файле, в котором выполняю макетирование . Если я использую глобальный элемент require
для включения чего-либо, даже после того, как я переопределил локальную копию, требуемые файлы по-прежнему будут иметь глобальная require
ссылка.
источник
global.require
. Переменные записываютсяmodule
по умолчанию, так как модули находятся в области видимости модулей.Ответы:
Ты можешь сейчас!
Я опубликовал proxyquire, который позаботится о переопределении глобальных требований внутри вашего модуля, пока вы его тестируете.
Это означает, что вам не нужно никаких изменений в вашем коде , чтобы внедрить макеты для необходимых модулей.
Proxyquire имеет очень простой API, который позволяет определить модуль, который вы пытаетесь протестировать, и передать макеты / заглушки для необходимых модулей за один простой шаг.
@Raynos прав, что традиционно вам приходилось прибегать к не очень идеальным решениям, чтобы достичь этого, или вместо этого заниматься разработкой снизу вверх.
Который является главной причиной, по которой я создал proxyquire - чтобы позволить разработку сверху вниз без каких-либо хлопот.
Посмотрите документацию и примеры, чтобы оценить, соответствует ли она вашим потребностям.
источник
proxyquire
!Лучшим вариантом в этом случае является макет методов возвращаемого модуля.
Что бы там ни было, большинство модулей node.js являются одиночными; две части кода, которые требуют () одного и того же модуля, получают одинаковую ссылку на этот модуль.
Вы можете использовать это и использовать что-то вроде sinon, чтобы макетировать предметы, которые требуются. Мокко тест следующим образом:
Sinon имеет хорошую интеграцию с chai для создания утверждений, и я написал модуль для интеграции sinon с mocha, чтобы упростить очистку от шпионов / заглушек (чтобы избежать загрязнения тестом.)
Обратите внимание, что underTest нельзя смоделировать таким же образом, поскольку underTest возвращает только функцию.
Другой вариант - использовать шутки. Следите за их страницей
источник
require('some_module')
, потому что весь ваш код использует один и тот же каталог node_modules. Во-вторых, статья объединяет пространство имен с синглетонами, что является своего рода ортогональным. В-третьих, эта статья чертовски старая (с точки зрения node.js), так что то, что могло быть верным в тот день, возможно, сейчас недействительно.innerLib.toCrazyCrap.restore()
и restub, или позвоните Sinon черезsinon.stub(innerLib, 'toCrazyCrap')
который позволяет изменять как тупиковые ведет себя:innerLib.toCrazyCrap.returns(false)
. Кроме того, rewire, кажется, очень похож наproxyquire
расширение выше.Я использую макет-требуют . Убедитесь, что вы определили свои макеты перед
require
тем, как тестировать модуль.источник
Насмешка
require
кажется мне отвратительным. Я лично попытался бы избежать этого и реорганизовать код, чтобы сделать его более тестируемым. Существуют различные подходы для обработки зависимостей.1) передать зависимости в качестве аргументов
Это сделает код универсально тестируемым. Недостатком является то, что вам нужно передавать зависимости, что может сделать код более сложным.
2) реализовать модуль как класс, затем использовать методы / свойства класса для получения зависимостей
(Это надуманный пример, где использование классов нецелесообразно, но оно передает идею) (пример ES6)
Теперь вы можете легко заглушить
getInnerLib
метод для проверки вашего кода. Код становится более подробным, но также и более простым для тестирования.источник
colors
модуль, которыйString.prototype
Если вы когда-либо использовали шутку, то вы, вероятно, знакомы с шутливой функцией шутки.
Используя "jest.mock (...)", вы можете просто указать строку, которая будет встречаться в операторе require где-нибудь в вашем коде, и всякий раз, когда требуется модуль, использующий эту строку, вместо этого будет возвращен mock-объект.
Например
полностью заменит все операции импорта / требования «firebase-admin» на объект, который вы вернули из этой «фабричной» функции.
Что ж, вы можете сделать это при использовании jest, потому что jest создает среду выполнения для каждого запускаемого модуля и внедряет в модуль «зацепленную» версию require, но вы не сможете сделать это без jest.
Я пытался достичь этого с помощью mock-require, но для меня это не сработало для вложенных уровней в моем источнике. Посмотрите на следующую проблему на github: mock-require не всегда вызывается с Mocha .
Для решения этой проблемы я создал два npm-модуля, которые вы можете использовать для достижения желаемого.
Вам нужен один babel-плагин и модуль-макер.
В вашем .babelrc используйте плагин babel-plugin-mock-require со следующими параметрами:
и в вашем тестовом файле используйте модуль jestlike-mock следующим образом:
jestlike-mock
Модуль еще очень рудиментарный и не имеет много документации , но там не много кода либо. Я ценю любые PR для более полного набора функций. Цель состоит в том, чтобы воссоздать всю функцию "jest.mock".Чтобы увидеть, как jest реализует это, можно посмотреть код в пакете "jest-runtime". См., Например, https://github.com/facebook/jest/blob/master/packages/jest-runtime/src/index.js#L734 , здесь они генерируют «автоматическую блокировку» модуля.
Надеюсь, это поможет ;)
источник
Ты не можешь Вы должны создать свой набор модульных тестов так, чтобы сначала тестировались самые младшие модули, а потом - модули более высокого уровня, для которых требуются модули.
Вы также должны предположить, что любой сторонний код и сам node.js хорошо протестированы.
Я полагаю, вы увидите, что в ближайшем будущем появятся насмешливые рамки, которые перезаписывают
global.require
Если вам действительно нужно внедрить макет, вы можете изменить свой код, чтобы открыть модульную область видимости.
Имейте в виду, что это подвергает риску
.__module
ваш API, и любой код может получить доступ к модульной области на свою собственную опасность.источник
Вы можете использовать издевательскую библиотеку:
источник
Простой код для макетов модулей для любопытных
Обратите внимание на части, где вы манипулируете
require.cache
и обратите внимание наrequire.resolve
метод, поскольку это секретный соус.Используйте как :
НО ... Proxyquire довольно круто, и вы должны использовать это. Он сохраняет ваши требования переопределенными только для тестов, и я настоятельно рекомендую это сделать.
источник