Comment se moquer de la classe ES6

Cet article a pour but de montrer comment simuler une classe en JavaScript aux fins des tests unitaires. La publication cible les développeurs qui arrivent sur ES6 à partir d'environnements dotés de fonctionnalités telles que l'injection de dépendance et les interfaces. La majeure partie de l'article couvrira ce qu'est une classe dans ES6 et pourquoi nous en avons besoin. Une fois que le modèle sous-jacent est couvert, se moquer de la même chose sera évident. Cet article vous guidera dans la création d'objets en JavaScript.

Littéral d'objet

Object est un premier citoyen en JavaScript. Le moyen incroyablement simple de créer un objet facilite le démarrage de ce langage. Voici un exemple d'objet.

var personne = {
  nom: 'Velu'
};

C'est aussi simple que cela. Pour créer un objet, vous commencez par object (et non par classe). En ce qui concerne, je dirais que JavaScript est vrai orienté objet (et les langages comme Java sont orientés classe comme vous le commencerez sera de créer des objets).

Étendons l’exemple ci-dessus pour ajouter un comportement à notre exemple d’objet, sayName.

var person1 = {
  nom: 'Velu',
  sayName: function () {
    console.log (this.name);
  }
}

Avec cet objet, si vous devez créer plusieurs objets, vous devez dupliquer la fonction sayName dans chacun des objets. Cela voudrait dire:

var person1 = {
  nom: 'Velu',
  sayName: function () {
    console.log (this.name);
  }
}
var person2 = {
  nom: 'Raj',
  sayName: function () {
    console.log (this.name);
  }
}

Si vous créez beaucoup de personnes, cela signifie qu'il y a beaucoup de duplication de code. Pour surmonter ceci vient la fonction constructeur.

Fonction constructeur

Écrivons un exemple de fonction constructeur et parlons-en:

fonction Personne (nom) {
  this.name = name;
  this.sayName = function () {
    console.log (this.name);
  }
}

À première vue, il s’agit là d’une autre fonction en JavaScript. Ce qui rend la fonction constructeur spéciale n’est pas la fonction elle-même mais son association avec le nouveau mot-clé. Donc, une fonction constructeur peut être utilisée comme dans:

var person1 = new Person ('Velu');

La ligne ci-dessus créera un objet et le code sera transformé en:

var person1 = {
  nom: 'Velu',
  sayName: function () {
    console.log (this.name);
  }
}

Maintenant, pour créer plus de personnes, il n’ya pas de duplication de code. Le plan est défini dans la fonction constructeur et JavaScript est converti par magie sous forme d'objet lors de l'exécution.

Avec cela, il n'y a pas de duplication de code, mais l'objet sous-jacent a toujours une pièce en double. La fonction sayName est définie une seule fois dans la fonction constructeur mais est toujours copiée dans chaque objet créé. Cela signifie plus de mémoire. Par exemple, si je crée 1 milliard de personnes dans mon Mac Book Pro, le processus de nœud se bloque sans mémoire. Cela implique un besoin de partager le modèle d'objet non seulement au moment du code, mais également au moment de l'exécution.

Prototype

Nous avons donc besoin d’un mécanisme permettant de partager les fonctions entre les objets. En JavaScript, le mécanisme de partage de code est encore un autre objet appelé prototype. Chaque objet JavaScript créé est doté d'un lien intégré appelé prototype à un autre objet. Cet objet est partagé par tous les objets créés à l'aide de la même fonction constructeur. La mise en page ci-dessous montre ceci:

Maintenant, l'étape évidente consiste à déplacer la fonction sayName d'un objet à son prototype. Le code ci-dessous fait ceci:

fonction Personne (nom) {
  this.name = name;
}
Person.prototype.sayName = function () {
    console.log (this.name);
}

JavaScript garantit également que 2 choses sont rendues possibles:

  1. Si une propriété est accédée sur un objet et n'est pas présente dans cet objet, elle sera recherchée et accessible dans son prototype.
  2. La référence "this" dans les fonctions attachées au prototype avec une liaison magique à l'objet sur lequel il est invoqué

Ainsi, l’invocation ci-dessous de sayName est assurée que celui-ci sera pointé sur un objet personne1 pendant l’exécution.

var person1 = new Person ('Velu');
person1.sayName ();

Classe ES6

Pour finir, la classe ES6 n’est finalement qu’un sucre syntaxique qui générera la fonction constructeur lors de l’exécution. La syntaxe de la classe apporte simplement ceci de manière plus concise:

classe Person {
  constructeur (nom) {
    this.name = name;
  }
  sayName () {
    console.log (this.name);
  }
}

Ayant compris quelle classe ES6 sous le capot, il reste un autre concept JavaScript à comprendre. Considérez les modules JavaScript suivants et leurs dépendances:

Dans cette structure, le module A importe B et C. Maintenant, lorsque le module B importe également C, le module chargé par A est réutilisé et non neuf. Cela signifie que si une classe ES6 est exportée du module C, sa définition peut être modifiée dans A et la définition modifiée sera reflétée dans C. Armés de cette compréhension des classes et du système de modules ES6, voyons enfin comment se moquer.

Se moquer de la classe ES6

Considérons le scénario de test suivant. L'employé dépend d'une aide de classe utilitaire pour obtenir un nombre aléatoire. Le module Employé ressemblerait à ceci:

const Helper = require ('./ helper');

classe Employee {
  constructeur (nom) {
    this.name = name;
  }

  getId () {
    const helper = new Helper ();
    const id = helper.getRandom ();

    return `$ {this.name} - $ {id}`;
  }
}

module.exports = Employé;

Le test unitaire de Employee doit simuler la méthode getRandom pour exécuter le test sur Employee.getId. Le flux ressemble à:

Maintenant, avec tous les détails que nous avons rassemblés jusqu'à présent, le code moqueur est évident et se présente comme suit:

const expect = require ('chai'). expect;
const sinon = require ('sinon');

const Employee = require ('../ src / employee');
const Helper = require ('../ src / helper');

describe ('test employé', () => {
  it ('devrait retourner le bon identifiant', () => {
    // Organiser
    sinon.stub (Helper.prototype, 'getRandom'). callsFake (() => 1);

    // Act
    const employé = nouvel employé ('Velu');
    const id = employee.getId ();

    // Assert
    s'attendre (id) .to.equals ('Velu-1');
  });
});

Fondamentalement, pour simuler une méthode sur la classe Helper, il suffit d’obtenir la référence de la fonction via le prototype de classe et de la remplacer. Cette ligne remplace la fonction getRandom pour toujours renvoyer 1 afin que l'opération Employee.getId puisse être validée.

sinon.stub (Helper.prototype, 'getRandom'). callsFake (() => 1);

La base de code pour cela peut être trouvée https://github.com/madhanganesh/es6-class-mocking-sample