Maison >interface Web >js tutoriel >Une brève analyse des problèmes associés et des solutions utilisant l'injection de dépendances dans Node.js_node.js

Une brève analyse des problèmes associés et des solutions utilisant l'injection de dépendances dans Node.js_node.js

WBOY
WBOYoriginal
2016-05-16 15:53:171266parcourir

Récemment, je me suis tourné vers l'Injection de dépendances pour m'aider à comprendre un moyen simple de séparer le code et faciliter les tests. Cependant, les modules de Node.js s'appuient sur l'API système fournie par Node, ce qui rend difficile de juger si les dépendances privées sont utilisées de manière appropriée. L'injection de dépendance générale est difficile à utiliser dans ce cas, mais ne perdez pas espoir pour l'instant.

exigerCauses du problème

Node.js peut facilement importer des dépendances selon vos besoins. Cela fonctionne très bien et est plus simple que les chargeurs de schéma AMD tels que RequireJS. Le problème survient lorsque nous nous moquons de ces dépendances. Si le chargement des modèles dans Node.js est contrôlé, comment pouvons-nous contrôler les pseudo-objets utilisés lors des tests ? Nous pouvons utiliser le mode vm de Node, via vm nous pouvons charger le modèle dans un nouveau contexte. En fonctionnant dans un nouveau contexte, nous pouvons contrôler la façon dont les exigences sont reflétées dans les méthodes du modèle.

Solution

Merci pour cet article, je peux maintenant vous proposer une assez bonne solution. Le code est ci-dessous :

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;
};

Vous pouvez également télécharger l'extrait de code ici Bien que le code ne soit pas publié dans l'article, il pourrait quand même nécessiter quelques explications. Lorsque nous testons, nous souhaitons charger ce module dans le test. , en utilisant la fonctionloadModule Load module test au lieu derequire.

Le premier paramètre, filePath, spécifie l'emplacement de recherche où nous souhaitons tester le modèle. Le deuxième paramètre, mocks, contient un objet dont les noms de propriétés correspondent aux noms du modèle dont nous essayons d'avoir besoin. Les valeurs spécifiées par ces attributs sont des pseudo-objets, utilisés pour remplacer les modèles généralement requis.

Essentiellement, il utilise vm pour charger et exécuter le modèle dans un autre "contexte". En d’autres termes, nous recréons des variables globales (telles que require et exports) afin de pouvoir les contrôler. Notez que nous avons écrit une nouvelle fonction require qui est disponible. Tout ce qu'il fait, c'est vérifier s'il existe une dépendance fictive pour le nom d'exécution, et si c'est le cas, je la délègue à la fonction require habituelle.

Exemple d'utilisation du chargeur de module

Si vous êtes encore un peu confus, vous pouvez consulter l'exemple de code ci-dessous pour voir comment il est utilisé dans son contexte, ce qui peut vous aider à le rendre plus clair. Tout d’abord, nous créons un module simple.

var fs = require('fs');
 
module.exports = {
// Do something with `fs`
}
想象一下这个很酷,对吗?不管怎样,现在我们测试那个模块,但是我们要模拟fs来看看它是怎么在内部使用的。
 
// Jasmine's syntax http://pivotal.github.com/jasmine/
describe('someModule', function() {
var loadModule = require('module-loader').loadModule;
var module, fsMock;
 
beforeEach(function() {
fsMock = {
 // a mock for `fs`
};
 
// load the module with mock fs instead of real fs
module = loadModule('./web-server.js', {fs: fsMock});
});
 
it('should work', function() {
// a test that utilizes the fact that we can now control `fs`
});
});

La principale chose à noter est qu'aux lignes 7 à 12, nous créons un objet factice pour fs et utilisons notre nouvelle fonction loadModule pour lier cet objet utilisé dans le petit module ci-dessus (je veux dire génial ! Rappelez-vous, ce qui est génial, droite?).

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn