Esta respuesta se basa en Andreas Köberle's answer.
No fue tan fácil para mí implementar y comprender su solución, así que lo explicaré con más detalle cómo funciona, y algunos escollos para evitar, con la esperanza de que ayudará a los futuros visitantes.
Así, en primer lugar la configuración:
estoy usando Karma como corredor de prueba y MochaJs como marco de pruebas.
usando algo como Squire no funcionó para mí, por alguna razón, cuando lo usé, el marco de la prueba arrojó errores:
TypeError: Cannot read property 'call' of undefined
RequireJs tiene la posibilidad de map ID del módulo a otro módulo IDS. También permite crear un require
function que usa un different config que el require
global.
Estas características son cruciales para que esta solución funcione.
Aquí está mi versión del código simulado, que incluye (mucho) comentarios (espero que sea comprensible). Lo envolví dentro de un módulo, para que las pruebas lo puedan requerir fácilmente.
define([], function() {
var count = 0;
var requireJsMock= Object.create(null);
requireJsMock.createMockRequire = function (mocks) {
//mocks is an object with the module ids/paths as keys, and the module as value
count++;
var map = {};
//register the mocks with unique names, and create a mapping from the mocked module id to the mock module id
//this will cause RequireJs to load the mock module instead of the real one
for (property in mocks) {
if (mocks.hasOwnProperty(property)) {
var moduleId = property; //the object property is the module id
var module = mocks[property]; //the value is the mock
var stubId = 'stub' + moduleId + count; //create a unique name to register the module
map[moduleId] = stubId; //add to the mapping
//register the mock with the unique id, so that RequireJs can actually call it
define(stubId, function() {
return module;
});
}
}
var defaultContext = requirejs.s.contexts._.config;
var requireMockContext = { baseUrl: defaultContext.baseUrl }; //use the baseUrl of the global RequireJs config, so that it doesn't have to be repeated here
requireMockContext.context = "context_" + count; //use a unique context name, so that the configs dont overlap
//use the mapping for all modules
requireMockContext.map = {
"*": map
};
return require.config(requireMockContext); //create a require function that uses the new config
};
return requireJsMock;
});
El mayor escollo me encontré, que literalmente me costó horas, fue la creación de la configuración RequireJS. Traté de (profundamente) copiarlo, y solo anulo las propiedades necesarias (como el contexto o el mapa). ¡Esto no funciona! Copie solo el baseUrl
, esto funciona bien.
Uso
Para usarlo, requieren en su prueba, crear la burla, y luego pasarlo a createMockRequire
. Por ejemplo:
var ModuleMock = function() {
this.method = function() {
methodCalled += 1;
};
};
var mocks = {
"ModuleIdOrPath": ModuleMock
}
var requireMocks = mocker.createMockRequire(mocks);
Y aquí un ejemplo de un archivo de prueba completa:
define(["chai", "requireJsMock"], function (chai, requireJsMock) {
var expect = chai.expect;
describe("Module", function() {
describe("Method", function() {
it("should work", function() {
return new Promise(function (resolve, reject) {
var handler = { handle: function() { } };
var called = 0;
var moduleBMock = function() {
this.method = function() {
methodCalled += 1;
};
};
var mocks = {
"ModuleBIdOrPath": moduleBMock
}
var requireMocks = requireJsMock.createMockRequire(mocks);
requireMocks(["js/ModuleA"], function (moduleA) {
try {
moduleA.method(); //moduleA should call method of moduleBMock
expect(called).to.equal(1);
resolve();
} catch (e) {
reject(e);
}
});
});
});
});
});
});
sólo estoy haciendo algunas cosas eval loco en Node.js para burlarse de la función 'define'. Sin embargo, hay algunas opciones diferentes. Publicaré una respuesta con la esperanza de que sea útil. – jergason
Para probar la unidad con Jasmine es posible que también desee echar un vistazo rápido a [Jasq] (https://github.com/biril/jasq). [Descargo de responsabilidad: Estoy manteniendo la lib] – biril
Si está probando en nodo env puede usar el paquete [require-mock] (https://github.com/ValeriiVasin/requirejs-mock). Le permite burlarse fácilmente de sus dependencias, reemplazar módulos, etc. Si necesita un navegador env con carga de módulo asíncrono, puede probar [Squire.js] (https://github.com/iammerrick/Squire.js/) – ValeriiVasin