Cómo simular dependencias para pruebas unitarias con módulos ES6


Estoy tratando de jugar con los módulos Ecmascript 6 usando webpack + traceur para transpilar a ES5 CommonJS, pero estoy teniendo problemas para probarlos con éxito.

He intentado usar el preprocesador Jest + traceur, pero el automocking y los nombres de dependencias parecen volverse locos, además parece que no puedo hacer que sourceMaps funcione con la depuración de Jest y node-inspector.

¿Hay un mejor marco para probar unitariamente los módulos ES6?

Author: Evan Layman, 2014-12-05

5 answers

He comenzado a emplear el estilo import * as obj dentro de mis pruebas, que importa todas las exportaciones de un módulo como propiedades de un objeto que luego se pueden burlar. Me parece que esto es mucho más limpio que el uso de algo como rewire o proxyquire o cualquier técnica similar.

No puedo hablar por traceur, que fue el marco utilizado en la pregunta, pero he encontrado que esto funciona con mi configuración de Karma, Jasmine y Babel, y lo estoy publicando aquí, ya que parece ser la pregunta más popular de esta tipo.

He usado esta estrategia más a menudo cuando necesito burlarme de las acciones Redux. He aquí un breve ejemplo:

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
});
 46
Author: carpeliam,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-16 18:14:40

Si está utilizando Webpack otra opción que tiene un poco más de flexibilidad que rewire es inject-loader.

Por ejemplo, en una prueba que se incluye con 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, de manera similar a proxyquire, al menos permite inyectar dependencias antes de importar, mientras que en rewire debe importar primero y luego rewire, lo que hace imposible burlarse de algunos componentes (por ejemplo, aquellos que tienen alguna inicialización).

 6
Author: djskinner,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-05-06 11:38:24

En realidad conseguí que esto funcionara dejando caer la broma y yendo con Karma + Jasmine + Webpack y usando https://github.com/jhnns/rewire para simular dependencias

 5
Author: Evan Layman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-07-30 18:09:14

Hola podría usar 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);
    });
});
 4
Author: JinVillaz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-31 19:57:58

Proxyquire le ayudará, pero no va a funcionar con módulos webpack+ES6 modernos, es decir, "alias".

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

that no funcionará. Mientras puedas burlarte de fs - no puedes burlarte de reductores. Debe especificar real el nombre de la dependencia, después de cualquier transformación de webpack o babel. Normalmente-nombre relativo a la ubicación del modulo1. Puede ser../../../ shared / core / reducers'. Puede que no.

Hay caída en soluciones - https://github.com/theKashey/proxyquire-webpack-alias (estable, basado en fork de proxyquire) o https://github.com/theKashey/resolveQuire (menos estable, se puede ejecutar sobre proxyquire original)

Ambos funcionan también, y se burlarán de cualquier módulo ES6(son buenos) de una manera proxyquire(es una buena manera)

 1
Author: Anton Korzunov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 22:12:29