Este es un ejemplo trivial que ilustra el quid de mi problema:
var innerLib = require('./path/to/innerLib');
function underTest() {
return innerLib.doComplexStuff();
}
module.exports = underTest;
Estoy tratando de escribir una prueba unitaria para este código. ¿Cómo puedo burlarme del requisito para el innerLib
sin burlar completamente la require
función?
Así que este soy yo tratando de burlarme de lo global require
y descubriendo que no funcionará incluso para hacer eso:
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;
}
};
El problema es que la require
función dentro del underTest.js
archivo en realidad no se ha burlado. Todavía apunta a la require
función global . Por lo tanto, parece que solo puedo require
simular la función dentro del mismo archivo en el que estoy haciendo el simulacro . Si uso el global require
para incluir algo, incluso después de haber anulado la copia local, los archivos requeridos seguirán teniendo require
referencia global
fuente
global.require
. Las variables escribenmodule
de forma predeterminada ya que los módulos tienen un alcance de módulo.Respuestas:
¡Tu puedes ahora!
Publiqué proxyquire que se encargará de anular el mundial requieren dentro de su módulo mientras se está probando la misma.
Esto significa que no necesita cambios en su código para inyectar simulacros para los módulos requeridos.
Proxyquire tiene una API muy simple que permite resolver el módulo que está tratando de probar y pasar simulaciones / apéndices para sus módulos requeridos en un solo paso simple.
@Raynos tiene razón en que tradicionalmente tenía que recurrir a soluciones no muy ideales para lograr eso o hacer un desarrollo ascendente
Cuál es la razón principal por la que creé proxyquire: para permitir el desarrollo de prueba de arriba hacia abajo sin ninguna molestia.
Eche un vistazo a la documentación y los ejemplos para determinar si se ajusta a sus necesidades.
fuente
proxyquire
!Una mejor opción en este caso es burlarse de los métodos del módulo que se devuelve.
Para bien o para mal, la mayoría de los módulos node.js son singletons; dos piezas de código que requieren () el mismo módulo obtienen la misma referencia a ese módulo.
Puede aprovechar esto y usar algo como sinon para burlarse de los elementos que se requieren. prueba de moca sigue:
Sinon tiene una buena integración con chai para hacer afirmaciones, y escribí un módulo para integrar sinon con mocha para permitir una limpieza más fácil de espías / trozos (para evitar la contaminación de prueba).
Tenga en cuenta que underTest no se puede burlar de la misma manera, ya que underTest solo devuelve una función.
Otra opción es usar simulacros de Jest. Seguimiento en su página
fuente
require('some_module')
, porque todo su código comparte el mismo directorio node_modules. En segundo lugar, el artículo combina espacio de nombres con singletons, que es algo ortogonal. En tercer lugar, ese artículo es bastante antiguo (en lo que respecta a node.js), por lo que lo que podría haber sido válido en ese momento posiblemente no lo sea ahora.innerLib.toCrazyCrap.restore()
y restub, o llamar sinon a través desinon.stub(innerLib, 'toCrazyCrap')
la cual le permite cambiar cómo se comporta el talón:innerLib.toCrazyCrap.returns(false)
. Además, rewire parece ser muy similar a laproxyquire
extensión anterior.Yo uso simulacro de requerimiento . Asegúrese de definir sus simulacros antes
require
del módulo que se probará.fuente
Burlarse me
require
parece un truco desagradable. Yo personalmente trataría de evitarlo y refactorizar el código para hacerlo más comprobable. Hay varios enfoques para manejar las dependencias.1) pasar dependencias como argumentos
Esto hará que el código sea universalmente comprobable. La desventaja es que necesita pasar dependencias, lo que puede hacer que el código se vea más complicado.
2) implementar el módulo como una clase, luego usar métodos / propiedades de clase para obtener dependencias
(Este es un ejemplo artificial, donde el uso de la clase no es razonable, pero transmite la idea) (ejemplo ES6)
Ahora puede tropezar fácilmente el
getInnerLib
método para probar su código. El código se vuelve más detallado, pero también más fácil de probar.fuente
colors
módulo popular que se meteString.prototype
)Si alguna vez has usado jest, entonces probablemente estés familiarizado con la función simulada de jest.
Usando "jest.mock (...)" simplemente puede especificar la cadena que ocurriría en una declaración require en su código en algún lugar y cada vez que se requiera un módulo usando esa cadena se devolvería un objeto simulado.
Por ejemplo
reemplazaría por completo todas las importaciones / requisitos de "firebase-admin" con el objeto que devolvió de esa función "fábrica".
Bueno, puede hacer eso cuando usa jest porque jest crea un tiempo de ejecución alrededor de cada módulo que ejecuta e inyecta una versión "enganchada" de require en el módulo, pero no podría hacerlo sin jest.
He intentado lograr esto con simulacro de requerimiento, pero para mí no funcionó para niveles anidados en mi fuente. Eche un vistazo al siguiente problema en github: mock-require no siempre se llama con Mocha .
Para abordar esto, he creado dos módulos npm que puede usar para lograr lo que desea.
Necesita un plugin de babel y un burlador de módulos.
En su .babelrc use el complemento babel-plugin-mock-require con las siguientes opciones:
y en su archivo de prueba use el módulo jestlike-mock de esta manera:
El
jestlike-mock
módulo sigue siendo muy rudimentario y no tiene mucha documentación, pero tampoco hay mucho código. Agradezco cualquier RP para un conjunto de características más completo. El objetivo sería recrear toda la función "jest.mock".Para ver cómo implementa jest, se puede buscar el código en el paquete "jest-runtime". Ver https://github.com/facebook/jest/blob/master/packages/jest-runtime/src/index.js#L734 por ejemplo, aquí generan un "bloqueo automático" de un módulo.
Espero que ayude ;)
fuente
No puedes Debe construir su conjunto de pruebas unitarias para que los módulos más bajos se prueben primero y los módulos de nivel superior que requieren módulos se prueben después.
También debe suponer que cualquier código de terceros y node.js en sí está bien probado.
Supongo que en un futuro próximo verán marcos burlones que sobrescribirán
global.require
Si realmente debe inyectar un simulacro, puede cambiar su código para exponer el alcance modular.
Tenga en cuenta que esto se expone
.__module
en su API y cualquier código puede acceder al alcance modular bajo su propio riesgo.fuente
Puedes usar la biblioteca de burlas :
fuente
Código simple para burlarse de módulos para curiosos
Observe las partes donde manipula el método
require.cache
y notarequire.resolve
ya que esta es la salsa secreta.Usar como :
PERO ... proxyquire es bastante impresionante y deberías usar eso. Mantiene sus anulaciones requeridas localizadas solo para pruebas y lo recomiendo encarecidamente.
fuente