Sinon: Можно ли заглушить отдельную служебную функцию?

Созданный на 12 сент. 2014  ·  18Комментарии  ·  Источник: sinonjs/sinon

Многие модули узлов экспортируют одну функцию (не функцию-конструктор, а «служебную» функцию общего назначения) как ее «module.exports». Можно ли использовать Sinon.js для отключения этой автономной функции?

// some module, "sum.js" that's "required" throughout the application
module.exports = function(a, b) {
    return a + b;
};

// test.js
var sum = require('sum');
...

beforeEach(function() {
    sumStub = sinon.stub(sum);
    // throws: TypeError: Attempted to wrap undefined property undefined as function
});

afterEach(function() {
   sumStub.restore();
});
...

Есть ли способ добиться этого?

Самый полезный комментарий

Попробуй это

import * as sum from './sum'
sinon.stub(sum, 'default', () => {
  // stubbed function
});

Все 18 Комментарий

К сожалению нет.

Для npm вы можете использовать https://github.com/thlorenz/proxyquire или аналогичный. Майкл Фезерс назвал бы это связующим звеном .

Это не изящно, но выполнимо.

Как только вы это сделаете, вы можете использовать Sinon, как обычно.

В долгосрочной перспективе вы можете захотеть сдвинуть свою архитектуру в сторону «объектных стыков», но это решение, которое работает сегодня. Подобные проекты существуют для RequireJS.

function MyFunction(){}
module.exports = function(){ return module.exports.MyFunction.apply(this, arguments) }
module.exports.MyFunction = MyFunction

Затем вы можете заглушить require ('./ MyFunction'). MyFunction и остальная часть вашего кода без изменений увидят заглушенную версию.

: dizzy:: dizzy_face:: dizzy:

На днях наткнулся на то же самое, вот что я сделал:

const proxyquire = require('proxyquire')
const sinon = require('sinon')
const sum = sinon.stub()

const ModuleWithDependency = proxyquire('module', {
  'sum': sum
})

очень хорошо работает в нашем случае.

При использовании CommonJS:

const myStubbedModule = function( absoluteModulePath ) {
  const stub = sinon.stub();
  require.cache[ require.resolve( absoluteModulePath ) ] = stub;
  return stub;
}

_Примечание_: в зависимости от того, транспилируете ли вы, вам может потребоваться:

require.cache[ require.resolve( absoluteModulePath ) ] = {
  default: stub,
  exports: stub
}

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

У меня было несколько обзоров кода, в которых люди подталкивали меня к взлому на уровне модуля Node через proxyquire, mock-require и т. Д. необходимо установить на место во время настройки теста. С proxyquire, по крайней мере, один может proxyquire () микро- / фикстурную версию приложения, что-то верхнего уровня и все заглушки будут добавлены во время загрузки, но решение этой проблемы на уровне языка JS, а не на уровне модуля узла, продолжается. показаться мне значительно более простым, с которым легче управлять последовательно и без опасностей (предостережение: пока кто-то не забывает восстанавливать).

Я сделал этот модуль, чтобы было легче вставлять модули-заглушки https://github.com/caiogondim/stubbable-decorator.js

Я просто играл с Sinon и нашел простое решение, которое, похоже, работает - просто добавьте аргументы в качестве второго аргумента.

const sumStub = sinon.stub(sum, 'arguments');
sumStub.withArgs(2, 2).returns(4);
sumStub.withArgs(3, 3).returns(6);

Попробуй это

import * as sum from './sum'
sinon.stub(sum, 'default', () => {
  // stubbed function
});

@ harryi3t - спасибо, что у меня сработало.

@ harryi3t У меня это не сработало при использовании модулей ES.
Ошибка: can't redefine non-configurable property "default"

Модули @elliottregan ES не подлежат замене в соответствии со СТАНДАРТОМ. У нас даже есть тесты, проверяющие это поведение. Тем не менее, как я здесь обсуждаю, вы все еще можете это сделать.

Многие люди на самом деле не тестируют модули ES, а транслируют модули ES (используя Webpack / Babel и т. Д.). В результате ES5 использует геттеры для имитации работы модулей ES. Возможно, вы это делаете, но попробуйте простой путь, который я предлагаю в связанной теме. mocha --register ... даст вам долгий путь.

Возможный обходной путь

(function (defineProperty) {
    Object.defineProperty = (obj, prop, desc) => {
        desc.configurable = true;
        return defineProperty(obj, prop, desc);
    };
})(Object.defineProperty);

@Sujimoshi Обходной путь для чего именно? Каков контекст вашего исправления? Кроме того, где люди могли бы положить исправление? В его текущем воплощении отсутствует слишком много информации, чтобы быть полезной. Это не поможет в исходном вопросе и не будет работать для модулей ES . Я предполагаю, что это касается кода, который был обработан Webpack 4, поскольку он может применяться (в зависимости от вашей инструментальной цепочки) к коду, написанному с использованием синтаксиса ES2015 +, который был _транспортирован_ в ES5, _эмулируя_ неизменность модулей ES через неконфигурируемые дескрипторы объектов. .

Попробуй это

import * as sum from './sum'
sinon.stub(sum, 'default', () => {
  // stubbed function
});

устарело сейчас.

Я просто переписал свой модуль ES6 из этого:

export default const doCoolStuff = () => {
  // do the cool stuff...
}

к этому:

export default {
  doCoolStuff: () => {
    // do the cool stuff...
  }
} 

Это немного неуклюже, но позволило мне обернуть функцию в заглушку.

сейчас почти 2021 год, это возможно?

сейчас почти 2021 год, это возможно?

Не сильно отличается от 2019 года.
Модули ES не изменились, CommonJS не изменился, JavaScript не изменился.

Была ли эта страница полезной?
0 / 5 - 0 рейтинги