2012-03-05 7 views
6

Tengo dificultades para escribir pruebas de alta calidad en mis módulos de nodo. El problema es el sistema de módulo requerido. Quiero poder verificar que un determinado módulo requerido tiene un método o su estado ha cambiado. Parece que hay 2 bibliotecas relativamente pequeñas que se pueden utilizar aquí: node-gently y mockery. Sin embargo, debido a su bajo 'perfil' me hace pensar que las personas no prueban esto, o hay otra forma de hacerlo de la que no tengo conocimiento.Probando Node.js, simulando y probando un módulo que se ha requerido?

¿Cuál es la mejor manera de burlar y probar un módulo que se ha requerido?

Respuesta

10

----------- --------------- ACTUALIZACIÓN

node-sandbox trabajos sobre los mismos principios que se establecen a continuación, pero está envuelto en un buen módulo. Me resulta muy agradable trabajar con.


--------------- awnser detallada ---------------

Después de mucho ensayo que tengo La mejor manera de probar los módulos de nodo de forma aislada, mientras que burlarse de todo es usar el método de Vojta Jina para ejecutar cada módulo dentro de una vm con un nuevo contexto como se explica here.

con este módulo VM de pruebas:

var vm = require('vm'); 
var fs = require('fs'); 
var path = require('path'); 

/** 
* Helper for unit testing: 
* - load module with mocked dependencies 
* - allow accessing private state of the module 
* 
* @param {string} filePath Absolute path to module (file to load) 
* @param {Object=} mocks Hash of mocked dependencies 
*/ 
exports.loadModule = function(filePath, mocks) { 
    mocks = mocks || {}; 

    // this is necessary to allow relative path modules within loaded file 
    // i.e. requiring ./some inside file /a/b.js needs to be resolved to /a/some 
    var resolveModule = function(module) { 
    if (module.charAt(0) !== '.') return module; 
    return path.resolve(path.dirname(filePath), module); 
    }; 

    var exports = {}; 
    var context = { 
    require: function(name) { 
     return mocks[name] || require(resolveModule(name)); 
    }, 
    console: console, 
    exports: exports, 
    module: { 
     exports: exports 
    } 
    }; 

    vm.runInNewContext(fs.readFileSync(filePath), context); 
    return context; 
}; 

es posible probar cada módulo con su propio contexto y fácilmente apagar todos dependencys externos.

fsMock = mocks.createFs(); 
mockRequest = mocks.createRequest(); 
mockResponse = mocks.createResponse(); 

// load the module with mock fs instead of real fs 
// publish all the private state as an object 
module = loadModule('./web-server.js', {fs: fsMock}); 

Recomiendo esta manera de escribir pruebas efectivas de forma aislada. Solo las pruebas de aceptación deberían llegar a toda la pila. Las pruebas de unidad e integración deben probar partes aisladas del sistema.

+0

¡Gracias por la gran respuesta! Sin embargo, tengo otra pregunta: No pude aprovechar esta técnica para anular las funciones privadas con las mías personalizadas en el módulo que se está probando. resulta en dos funciones: una en el ámbito local y otra en el ámbito global, con el módulo bajo prueba siempre llamando a la versión global/original. – Attilah

5

Creo que el patrón de burla es muy bueno. Dicho esto, generalmente opto por enviar dependencias como parámetros a una función (similar a pasar dependencias en el constructor).

// foo.js 
module.exports = function(dep1, dep2) { 
    return { 
     bar: function() { 
      // A function doing stuff with dep1 and dep2 
     } 
    } 
} 

Al probar, puedo enviar simulaciones, objetos vacíos en su lugar, lo que parezca apropiado. Tenga en cuenta que no hago esto para todas las dependencias, básicamente solo IO: no siento la necesidad de probar que mi código llame al path.join o lo que sea.

creo que el "perfil bajo" que está haciendo nervioso se debe a un par de cosas:

  • Algunas personas estructuran su código similar a la mía
  • Algunas personas tienen su propio personal para cumplir la misma objetivo como burla y otros (es un módulo muy simple)
  • Algunas personas no prueban en unidades tales cosas, en lugar de eso, activan una instancia de su aplicación (y db, etc.) y las prueban en contra de eso. Pruebas más limpias, y el servidor es tan rápido que no afecta el rendimiento de la prueba.

En resumen, si crees que la burla es adecuada para ti, ¡adelante!

+0

El problema con esto es la prueba de la unidad está afectando a la base de datos que no es ideal. –

+1

@beck: solo si envía un DB real al realizar la prueba. –

1

Te burlas fácilmente requiere mediante el uso de "a": https://npmjs.org/package/a

//Example faking require('./foo') in unit test: 
var fakeFoo = {}; 
var expectRequire = require('a').expectRequire; 
expectRequire('./foo).return(fakeFoo); 


//in sut: 
var foo = require('./foo); //returns fakeFoo