如何使用Jest模拟ES6模块导入?

时间:2016-11-07 12:19:32

标签: javascript node.js mocking ecmascript-6 jestjs

我开始认为这是不可能的,但无论如何我想问。

我想测试我的一个ES6模块以特定方式调用另一个ES6模块。使用Jasmine,这非常容易 -

应用代码:

//myModule-test.js
import myModule from '../myModule';
import dependency from '../dependency';

describe('myModule', () => {
  it('calls the dependency with double the input', () => {
    spyOn(dependency, 'doSomething');

    myModule(2);

    expect(dependency.doSomething).toHaveBeenCalledWith(4);
  });
});

测试代码:

import

与Jest相同的是什么?我觉得这样做是一件很简单的事情,但我一直在试图弄清楚我的头发。

我最接近的是用require替换// myModule.js export default (x) => { const dependency = require('./dependency'); // yuck dependency.doSomething(x * 2); } //myModule-test.js describe('myModule', () => { it('calls the dependency with double the input', () => { jest.mock('../dependency'); myModule(2); const dependency = require('../dependency'); // also yuck expect(dependency.doSomething).toBeCalledWith(4); }); }); s,并将它们移到测试/函数中。这些都不是我想要做的事情。

dependency.js

对于奖励积分,当var Post = new mongoose.Schema({ name:String, post:[{ like:String, comment:[{ date:String, username:String, detail:{ time:String, day:String } }] }] }) 内的函数是默认导出时,我很乐意让整个事情发挥作用。但是,我知道监视默认导出在Jasmine中不起作用(或者至少我永远无法使用它),所以我并不是希望Jest中也可以这样做。

6 个答案:

答案 0 :(得分:167)

我已经能够通过使用涉及import *的黑客来解决这个问题。它甚至适用于命名和默认导出!

对于命名导出:

// dependency.js
export const doSomething = (y) => console.log(y)

// myModule.js
import { doSomething } from './dependency';

export default (x) => {
  doSomething(x * 2);
}

// myModule-test.js
import myModule from '../myModule';
import * as dependency from '../dependency';

describe('myModule', () => {
  it('calls the dependency with double the input', () => {
    dependency.doSomething = jest.fn(); // Mutate the named export

    myModule(2);

    expect(dependency.doSomething).toBeCalledWith(4);
  });
});

或者是默认导出:

// dependency.js
export default (y) => console.log(y)

// myModule.js
import dependency from './dependency'; // Note lack of curlies

export default (x) => {
  dependency(x * 2);
}

// myModule-test.js
import myModule from '../myModule';
import * as dependency from '../dependency';

describe('myModule', () => {
  it('calls the dependency with double the input', () => {
    dependency.default = jest.fn(); // Mutate the default export

    myModule(2);

    expect(dependency.default).toBeCalledWith(4); // Assert against the default
  });
});

正如Mihai Damian在下面正确地指出的那样,这正在改变dependency的模块对象,因此它会“泄漏”到其他测试中。因此,如果您使用此方法,则应存储原始值,然后在每次测试后重新设置。 要使用Jest轻松完成此操作,请使用spyOn()方法而不是jest.fn(),因为它支持轻松恢复其原始值,因此避免在提及“泄漏”之前。

答案 1 :(得分:118)

你必须自己模拟模块并设置间谍:

import myModule from '../myModule';
import dependency from '../dependency';
jest.mock('../dependency', () => ({
  doSomething: jest.fn()
}))

describe('myModule', () => {
  it('calls the dependency with double the input', () => {
    myModule(2);
    expect(dependency.doSomething).toBeCalledWith(4);
  });
});

答案 2 :(得分:37)

为Andreas答案添加更多内容。我有与ES6代码相同的问题,但不想改变导入。看起来很丑陋。所以我做了这个

import myModule from '../myModule';
import dependency from '../dependency';
jest.mock('../dependency');

describe('myModule', () => {
  it('calls the dependency with double the input', () => {
    myModule(2);
  });
});

并在"中添加了dependency.js。 __ 模拟 __"与dependency.js并行的文件夹。这对我有用。此外,这使我可以选择从模拟实现中返回合适的数据。确保为要模拟的模块提供正确的路径。

答案 3 :(得分:29)

快速前进到2020年,我发现此博客文章是解决方案: Jest mock default and named export

仅使用ES6模块语法:

// esModule.js
export default 'defaultExport';
export const namedExport = () => {};

// esModule.test.js
jest.mock('./esModule', () => ({
  __esModule: true, // this property makes it work
  default: 'mockedDefaultExport',
  namedExport: jest.fn(),
}));

import defaultExport, { namedExport } from './esModule';
defaultExport; // 'mockedDefaultExport'
namedExport; // mock function

您还需要知道的一件事(花了我一段时间才弄清楚)是,您不能在测试内调用jest.mock()。您必须在模块的顶层调用它。但是,如果要为不同的测试设置不同的模拟,则可以在各个测试中调用mockImplementation()。

答案 4 :(得分:0)

我用另一种方式解决了这个问题。假设您有dependency.js

export const myFunction = () => { }

除以下内容外,我还创建了一个depdency.mock.js文件:

export const mockFunction = jest.fn();

jest.mock('dependency.js', () => ({ myFunction: mockFunction }));

在测试中,在导入具有惯用性的文件之前,

import { mockFunction } from 'dependency.mock'
import functionThatCallsDep from './tested-code'

it('my test', () => {
    mockFunction.returnValue(false);

    functionThatCallsDep();

    expect(mockFunction).toHaveBeenCalled();

})

答案 5 :(得分:0)

问题已经回答,但是您可以这样解决:

dependency.js

module.exports.doSomething = (x) => x

myModule.js:

const { doSomething } = require('./dependency')
module.exports = (x) => doSomething(x * 2)

myModule.spec.js:

jest.mock('../dependency')
const { doSomething } = require('../dependency')
const myModule = require('../myModule')
describe('myModule', () => {
    it('calls the dependency with double the input', () => {
      doSomething.mockImplementation((x) => x * 10)

      myModule(2);

      expect(doSomething).toHaveBeenCalledWith(4);
      console.log(myModule(2)) // 40
    });
  });