web-dev-qa-db-fra.com

Comment se moquer des dépendances pour les tests unitaires avec les modules ES6

J'essaie de jouer avec les modules Ecmascript 6 en utilisant webpack + traceur pour les transpiler vers ES5 CommonJS, mais j'ai du mal à les tester avec succès.

J'ai essayé d'utiliser le préprocesseur Jest + traceur, mais les noms d'automockage et de dépendance semblent devenir délicats, et je n'arrive pas à faire fonctionner sourceMaps avec Jest et le débogage de l'inspecteur de nœuds.

Existe-t-il un meilleur cadre pour tester les modules ES6 à l'unité?

56
Evan Layman

En fait, cela a fonctionné en supprimant Jest et en utilisant Karma + Jasmine + Webpack et en utilisant https://github.com/jhnns/rewire pour simuler les dépendances

5
Evan Layman

J'ai commencé à utiliser le import * as obj style dans mes tests, qui importe toutes les exportations d'un module en tant que propriétés d'un objet qui peut ensuite être moqué. Je trouve que c'est beaucoup plus propre que d'utiliser quelque chose comme rewire ou proxyquire ou toute autre technique similaire.

Je ne peux pas parler de traceur qui était le cadre utilisé dans la question, mais j'ai trouvé que cela fonctionnait avec ma configuration de Karma, Jasmine et Babel, et je le poste ici car cela semble être le plus populaire question de ce type.

J'ai utilisé cette stratégie le plus souvent lorsque je dois simuler des actions Redux. Voici un petit exemple:

import * as exports from 'module-you-want-to-mock';
import SystemUnderTest from 'module-that-uses-above-module';

describe('your module', () => {
  beforeEach(() => {
    spyOn(exports, 'someNamedExport');  // mock a named export
    spyOn(exports, 'default');          // mock the default export
  });
  // ... now the above functions are mocked
});
52
carpeliam

Si vous utilisez Webpack, une autre option qui a un peu plus de flexibilité que le recâblage est inject-loader .

Par exemple, dans un test fourni avec Webpack:

describe('when an alert is dismissed', () => {

  // Override Alert as we need to mock dependencies for these tests
  let Alert, mockPubSub

  beforeEach(() => {
    mockPubSub = {}
    Alert =  require('inject!./alert')({
      'pubsub-js': mockPubSub
    }).Alert
  })

  it('should publish \'app.clearalerts\'', () => {
    mockPubSub.publish = jasmine.createSpy()
    [...]
    expect(mockPubSub.publish).toHaveBeenCalled()
  })
})

inject-loader, d'une manière similaire à proxyquire, permet au moins d'injecter des dépendances avant d'importer, tandis que dans recâbler, vous devez d'abord importer, puis recâbler, ce qui rend impossible de se moquer de certains composants (par exemple ceux qui ont une certaine initialisation).

6
djskinner

Salut, vous pouvez utiliser proxyquire:

import assert from 'assert';
import sinon from 'sinon';
import Proxyquire from 'proxyquire';

let proxyquire = Proxyquire.noCallThru(),
    pathModelLoader = './model_loader';

describe('ModelLoader module.', () => {
    it('Should load all models.', () => {
        let fs, modelLoader, ModelLoader, spy, path;
        fs = {
            readdirSync(path) {
                return ['user.js'];
            }
        };
        path = {
            parse(data) {
                return {name: 'user'};
            }
        };
        ModelLoader = proxyquire(pathModelLoader, {'fs': fs, 'path': path});
        modelLoader = new ModelLoader.default();
        spy = sinon.spy(modelLoader, 'loadModels');
        modelLoader.loadModels();
        assert(spy.called);
    });
});
5
JinVillaz

Proxyquire vous aidera, mais cela ne fonctionnera pas avec les modules webpack + ES6 modernes, c'est-à-dire les "alias".

import fs from 'fs';
import reducers from 'core/reducers';
...
proxyquire('../module1', {
  'fs': mockFs,  // this gonna work
  'core/reducers': mockReducers // what about this?
});

that ne fonctionnera pas. Tant que vous pouvez vous moquer de fs - vous ne pouvez pas vous moquer des réducteurs. Vous devez spécifier real nom de la dépendance, après toute transformation webpack ou babel. Normalement - nom relatif à l'emplacement du module1. Peut être '../../../shared/core/reducers'. Peut être pas.

Il y a des solutions de baisse - https://github.com/theKashey/proxyquire-webpack-alias (stable, basé sur fork de proxyquire) ou https://github.com/ theKashey/resolQuire (moins stable, peut être exécuté sur proxyquire d'origine)

Les deux fonctionnent également, et se moqueront de tout module ES6 (ils sont très bons) de manière proxyquire (c'est une bonne façon)

1
Anton Korzunov