Sinon: ¿Es posible eliminar una función de utilidad independiente?

Creado en 12 sept. 2014  ·  18Comentarios  ·  Fuente: sinonjs/sinon

Muchos módulos de nodo exportan una sola función (no una función de constructor, sino una función de "utilidad" de propósito general) como su "módulo.exporta". ¿Es posible usar Sinon.js para eliminar esta función independiente?

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

¿Hay alguna forma de lograrlo?

Comentario más útil

Prueba esto

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

Todos 18 comentarios

Lamentablemente no.

Para npm puede usar https://github.com/thlorenz/proxyquire o similar. Michael Feathers llamaría a esto una costura de enlace .

No es elegante, pero factible.

Una vez que tenga eso en su lugar, puede usar Sinon como lo haría normalmente.

A largo plazo, es posible que desee mover su arquitectura hacia _ costuras de objetos_, pero es una solución que funciona en la actualidad. Existen proyectos similares para RequireJS.

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

Luego, puede requerir stub ('./ MyFunction'). MyFunction y el resto de su código verán la edición stub sin cambios.

: mareado:: cara_dizzy:: mareado:

Me encontré con lo mismo el otro día, esto es lo que hice:

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

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

funciona bastante bien para nuestro caso.

Si usa CommonJS:

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

_Nota_: Dependiendo de si está transpilando, es posible que deba hacer:

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

A menudo, durante las pruebas, necesitaré insertar un talón para una prueba específica. El enfoque de función de envoltura que tomé me permite modificar la base de código e insertar mis códigos auxiliares cuando quiera, sin tener que adoptar un enfoque de código auxiliar primero o jugar whack-a-mole con módulos que tienen referencias a los otros módulos que estoy tratando de talón y reemplácelo en su lugar.

He tenido una serie de revisiones de código en las que la gente me ha empujado a piratear la capa del módulo Node, a través de proxyquire, mock-require , etc., y comienza de manera simple y parece menos cruda, pero se convierte en un desafío muy difícil de obtener los stubs. necesario en su lugar durante la configuración de la prueba. Con proxyquire, al menos uno puede proxyquire () una versión de la aplicación del tamaño de un micro / dispositivo, algo de nivel superior, y todos los stubs se incorporarán durante su carga, pero abordar esto en un nivel de lenguaje JS en lugar de un módulo de nodo continúa para parecerme significativamente más sencillo y más fácil de administrar de manera consistente y sin peligro (advertencia: siempre que uno recuerde restaurar).

Hice este módulo para crear módulos stub más fácilmente https://github.com/caiogondim/stubbable-decorator.js

Estaba jugando con Sinon y encontré una solución simple que parece estar funcionando: solo agregue 'argumentos' como segundo argumento

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

Prueba esto

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

@ harryi3t - gracias que funcionó para mí.

@ harryi3t Eso no funcionó para mí, usando módulos ES.
Error: can't redefine non-configurable property "default"

Los módulos de Incluso tenemos pruebas que cubren este comportamiento. Sin embargo, todavía puedes hacerlo, como explico aquí .

Mucha gente no está probando los módulos ES, sino los módulos ES transpilados (usando Webpack / Babel, etc.). El ES5 resultante utiliza captadores para emular cómo funcionan los módulos ES. Es posible que esté haciendo eso, pero pruebe la ruta simple que sugiero en el hilo vinculado. mocha --register ... te lleva muy lejos.

Posible solución

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

@Sujimoshi ¿ Solución alternativa para qué exactamente? ¿Cuál es el contexto de su solución? Además, ¿dónde pondría la gente la solución? En su encarnación actual, le falta demasiada información para ser útil. No ayudaría a la pregunta original y no funcionará para los módulos ES . Supongo que se trata de código que ha sido procesado por Webpack 4, ya que podría aplicarse (dependiendo de su cadena de herramientas) al código escrito con la sintaxis ES2015 + que se ha _transpilado_ en ES5, _emulando_ la inmutabilidad de los módulos ES a través de descriptores de objetos no configurables .

Prueba esto

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

en desuso ahora.

Acabo de reescribir mi módulo ES6 de esto:

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

a esto:

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

Es un poco torpe, pero me permitió envolver la función en un código auxiliar.

ahora es casi el 2021, ¿es posible?

ahora es casi el 2021, ¿es posible?

No muy diferente a 2019.
Los módulos ES no han cambiado, CommonJS no ha cambiado, JavaScript no ha cambiado.

¿Fue útil esta página
0 / 5 - 0 calificaciones