226 votes

Comment accéder et tester une fonction interne (non exportée) dans un module node.js ?

J'essaie de comprendre comment tester les fonctions internes (c'est-à-dire non exportées) dans nodejs (de préférence avec mocha ou jasmine). Et je n'ai aucune idée !

Disons que j'ai un module comme celui-ci :

function exported(i) {
   return notExported(i) + 1;
}

function notExported(i) {
   return i*2;
}

exports.exported = exported;

Et le test suivant (moka) :

var assert = require('assert'),
    test = require('../modules/core/test');

describe('test', function(){

  describe('#exported(i)', function(){
    it('should return (i*2)+1 for any given i', function(){
      assert.equal(3, test.exported(1));
      assert.equal(5, test.exported(2));
    });
  });
});

Existe-t-il un moyen de tester l'unité notExported sans l'exporter puisqu'elle n'est pas destinée à être exposée ?

1voto

Alberto wemass Points 11

J'ai utilisé une approche différente, sans aucune dépendance : Avoir une exportation __testing avec toutes les fonctions locales que je veux tester, dont la valeur dépend de NODE_ENV, donc elle n'est accessible que sur les tests :

// file.ts
const localFunction = () => console.log('do something');
const localFunciton2 = () => console.log('do something else');
export const exportedFunction = () => {
    localFunction();
    localFunciton2();
}
export const __testing = (process.env.NODE_ENV === 'test') ? {
    localFunction, localFunction2
} : void 0;

// file.test.ts
import { __testing, exportedFunction } from './file,ts'
const { localFunction, localFunction2 } = __testing!;
// Now you can test local functions

0voto

srosh Points 124

Vous pouvez créer un nouveau contexte en utilisant vm et évalue le fichier js qu'il contient, un peu comme le fait repl. Vous avez alors accès à tout ce qu'il déclare.

0voto

Abhishek Divekar Points 716

Ce n'est pas une pratique recommandée, mais si vous ne pouvez pas utiliser la fonction rewire comme suggéré par @Antoine, vous pouvez toujours simplement lire le fichier et utiliser eval() .

var fs = require('fs');
const JsFileString = fs.readFileSync(fileAbsolutePath, 'utf-8');
eval(JsFileString);

J'ai trouvé cela utile lors de tests unitaires de fichiers JS côté client pour un ancien système.

Les fichiers JS configureraient un grand nombre de variables globales sous le nom de window sans aucune require(...) y module.exports (de toute façon, il n'y avait pas de module de regroupement comme Webpack ou Browserify pour supprimer ces déclarations).

Plutôt que de remanier l'ensemble du code, cela nous a permis d'intégrer des tests unitaires dans notre JS côté client.

0voto

Ian Carter Points 51

Essentiellement, vous devez fusionner le contexte source avec les cas de test - une façon de le faire serait d'utiliser une petite fonction d'aide enveloppant les tests.

demo.js

const internalVar = 1;

demo.test.js

const importing = (sourceFile, tests) => eval(`${require('fs').readFileSync(sourceFile)};(${String(tests)})();`);

importing('./demo.js', () => {
    it('should have context access', () => {
        expect(internalVar).toBe(1);
    });
});

0voto

tyler1205 Points 49

eval ne fonctionne pas vraiment par lui-même (il ne fonctionnera qu'avec les fonctions de premier niveau ou les fonctions var ), vous ne pouvez pas capturer les variables de haut niveau qui sont déclarées avec let ou const dans le contexte actuel avec eval, cependant, en utilisant une vm et en l'exécutant dans le contexte actuel sera vous permettent d'accéder tous les variables de niveau supérieur après son exécution...

eval("let local = 42;")
// local is undefined/undeclared here

const vm = require("vm")
vm.runInThisContext("let local = 42;");
// local is 42 here

...bien que les déclarations ou les affectations dans le module "importé" puissent entrer en conflit avec tout ce qui est déjà déclaré/défini dans le contexte actuel au moment où le vm démarre s'ils partagent le même nom.

Voici une solution médiocre. Cependant, cela ajoutera un peu de code inutile à vos modules/unités importés, et votre suite de tests devra exécuter chaque fichier directement afin d'exécuter ses tests unitaires de cette manière. L'exécution directe de vos modules pour faire autre chose que l'exécution de ses tests unitaires serait hors de question sans encore plus de code.

Dans le module importé, vérifiez si le fichier est le module principal, si oui, exécutez les tests :

const local = {
  doMath() {return 2 + 2}
};

const local2 = 42;

if (require.main === module) {
  require("./test/tests-for-this-file.js")({local, local2});
} 

Puis dans le fichier/module de test qui importe le module cible :

module.exports = function(localsObject) {
  // do tests with locals from target module
}

Maintenant, exécutez votre module cible directement avec node MODULEPATH pour exécuter ses tests.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X