Sinon: É possível fazer o stub de uma função de utilitário autônomo?

Criado em 12 set. 2014  ·  18Comentários  ·  Fonte: sinonjs/sinon

Muitos módulos de nó exportam uma única função (não uma função de construtor, mas uma função "utilitária" de propósito geral) como seu "módulo.exporta". É possível usar o Sinon.js para fazer o stub dessa função autônoma?

// 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();
});
...

Existe alguma maneira de conseguir isso?

Comentários muito úteis

Tente isto

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

Todos 18 comentários

Infelizmente não.

Para npm, você pode usar https://github.com/thlorenz/proxyquire ou semelhante. Michael Feathers chamaria isso de costura de ligação .

Não é elegante, mas factível.

Depois de fazer isso, você pode usar o Sinon normalmente.

No longo prazo, você pode querer mover sua arquitetura em direção a _object costuras_, mas é uma solução que funciona hoje. Existem projetos semelhantes para RequireJS.

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

Em seguida, você pode criar um stub para require ('./ MyFunction'). MyFunction e o resto do seu código sem alteração verá a edição em stub.

: tonto:: tonto_face:: tonto:

Encontrei a mesma coisa outro dia, eis o que fiz:

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

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

funciona muito bem para o nosso caso.

Se estiver usando CommonJS:

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

_Nota_: Dependendo se você está transpilando, você pode precisar fazer:

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

Freqüentemente, durante os testes, preciso inserir um esboço para um teste específico. A abordagem de função de invólucro que usei me permite modificar a base de código e inserir meus stubs sempre que eu quiser, sem ter que adotar uma abordagem stub-first ou jogar whack-a-mole com módulos tendo referências a outros módulos que estou tentando stub e substituir no local.

Eu tive uma série de revisões de código em que as pessoas me incentivaram a hackear a camada do módulo Node, via proxyquire, mock-require etc. necessário no local durante a configuração do teste. Com proxyquire, pelo menos um pode proxyquire () uma versão do tamanho de um micro / dispositivo elétrico do aplicativo, algo de nível superior, e todos os stubs serão trazidos durante o carregamento, mas lidar com isso em um nível de linguagem JS em vez de nível de módulo Node continua para me parecer significativamente mais simples e fácil de gerenciar de forma consistente e sem perigo (advertência: desde que se lembre de restaurar).

Fiz este módulo para módulos stub mais facilmente https://github.com/caiogondim/stubbable-decorator.js

Eu estava apenas brincando com o Sinon e encontrei uma solução simples que parece estar funcionando - basta adicionar 'argumentos' como um segundo argumento

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

Tente isto

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

@ harryi3t - obrigado, funcionou para mim.

@ harryi3t Isso não funcionou para mim, usando os Módulos ES.
Erro: can't redefine non-configurable property "default"

Módulos @elliottregan ES não são stubbable de acordo com o PADRÃO. Temos até testes que cobrem esse comportamento. Você ainda pode fazer isso, como discuto aqui .

Muitas pessoas não estão realmente testando os Módulos ES, mas sim os Módulos ES transpilados (usando Webpack / Babel, etc). O ES5 resultante usa getters para emular como os Módulos ES funcionam. Você pode estar fazendo isso, mas tente o caminho simples que sugiro no tópico vinculado. mocha --register ... leva você longe.

Possível solução

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

@Sujimoshi Solução alternativa para o quê exatamente? Qual é o contexto para sua correção? Além disso, onde as pessoas colocariam a correção? Em sua encarnação atual, está faltando um pouco de informação demais para ser útil. Isso não ajudaria na pergunta original e não funcionaria para os Módulos ES . Eu estou supondo que se refere ao código que foi processado pelo Webpack 4, pois pode se aplicar (dependendo de sua cadeia de ferramentas) ao código escrito usando a sintaxe ES2015 + que foi _transpilada_ no ES5, _emulando_ a imutabilidade dos Módulos ES por meio de descritores de objeto não configuráveis .

Tente isto

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

obsoleto agora.

Acabei de reescrever meu módulo ES6 a partir deste:

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

para isso:

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

É um pouco desajeitado, mas me permitiu envolver a função em um esboço.

agora é quase 2021, é possível?

agora é quase 2021, é possível?

Não é muito diferente de 2019.
Módulos ES não mudaram, CommonJS não mudou, JavaScript não mudou.

Esta página foi útil?
0 / 5 - 0 avaliações