Javascript 如何使用 ES6 模块模拟单元测试的依赖项

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/27323031/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 00:01:23  来源:igfitidea点击:

How to mock dependencies for unit tests with ES6 Modules

javascriptunit-testingecmascript-6traceurjestjs

提问by Evan Layman

I'm trying to fiddle with Ecmascript 6 modules using webpack + traceur to transpile to ES5 CommonJS, but I'm having trouble successfully unit testing them.

我正在尝试使用 webpack + traceur 来处理 Ecmascript 6 模块以转换为 ES5 CommonJS,但是我无法成功地对它们进行单元测试。

I tried using Jest + traceur preprocessor, but the automocking and dependency names seem to get screwy, plus I can't seem to get sourceMaps to work with Jest and node-inspector debugging.

我尝试使用 Jest + traceur 预处理器,但是 automocking 和依赖项名称似乎变得很奇怪,而且我似乎无法让 sourceMaps 与 Jest 和节点检查器调试一起使用。

Is there a better framework to unit test ES6 modules?

有没有更好的框架来单元测试 ES6 模块?

采纳答案by Evan Layman

I actually got this to work by dropping Jest and going with Karma + Jasmine + Webpack and using https://github.com/jhnns/rewireto mock dependencies

我实际上通过删除 Jest 并使用 Karma + Jasmine + Webpack 并使用https://github.com/jhnns/rewire来模拟依赖项来实现这一点

回答by carpeliam

I've started employing the import * as objstyle within my tests, which imports all exports from a module as properties of an object which can then be mocked. I find this to be a lot cleaner than using something like rewire or proxyquire or any similar technique.

我已经开始import * as obj在我的测试中使用这种样式,它将模块中的所有导出作为对象的属性导入,然后可以对其进行模拟。我发现这比使用 rewire 或 proxyquire 或任何类似技术要干净得多。

I can't speak for traceur which was the framework used in the question, but I've found this to work with my setup of Karma, Jasmine, and Babel, and I'm posting it here as this seems to be the most popular question of this type.

我不能说问题中使用的框架 traceur,但我发现它适用于我的 Karma、Jasmine 和 Babel 设置,我将它发布在这里,因为这似乎是最受欢迎的这种类型的问题。

I've used this strategy most often when needing to mock Redux actions. Here's a short example:

在需要模拟 Redux 操作时,我最常使用这种策略。这是一个简短的例子:

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

回答by djskinner

If you are using Webpack another option that has a little more flexibility than rewire is inject-loader.

如果你正在使用 Webpack,另一个比 rewire 更灵活的选项是inject-loader

For example, in a test that is bundled with Webpack:

例如,在与 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, in a similar manner to proxyquire at least allows one to inject dependencies before importing whereas in rewire you must import first and then rewire which makes mocking some components (e.g. those that have some initialization) impossible.

注入加载器,以类似于 proxyquire 的方式,至少允许在导入之前注入依赖项,而在重新连接中,您必须先导入然后重新连接,这使得模拟某些组件(例如,具有某些初始化的组件)变得不可能。

回答by JinVillaz

Hi you could use proxyquire:

嗨,您可以使用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);
    });
});

回答by Anton Korzunov

Proxyquire will help you, but it not gonna to work with modern webpack+ES6 modules, ie "aliases".

Proxyquire 会帮助你,但它不会与现代 webpack+ES6 模块一起工作,即“别名”。

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

thatwill not work. As long you can mock fs - you cannot mock reducers. You have to specify realname of dependency, after any webpack or babel transformation. Normally - name relative to module1 location. May be '../../../shared/core/reducers'. May be not.

that不管用。只要您可以模拟 fs - 您就不能模拟减速器。real在任何 webpack 或 babel 转换之后,您必须指定依赖项的名称。通常 - 相对于 module1 位置的名称。可能是“../../../shared/core/reducers”。也许不吧。

There is drop in solutions - https://github.com/theKashey/proxyquire-webpack-alias(stable, based on fork of proxyquire) or https://github.com/theKashey/resolveQuire(less stable, can be run upon original proxyquire)

解决方案有所下降 - https://github.com/theKashey/proxyquire-webpack-alias(稳定,基于 proxyquire 的分支)或https://github.com/theKashey/resolveQuire(不太稳定,可以运行)原始代理需要)

Both of them works as well, and will mock any ES6 module(they are dam good) in a proxyquire way(it is a good way)

它们都可以工作,并且会以代理方式模拟任何 ES6 模块(它们很好)(这是一个好方法)