提问者:小点点

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


我想测试我的一个ES6模块以特定的方式调用另一个ES6模块。有了茉莉,这是非常容易的--

应用程序代码:

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

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

和测试代码:

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

什么是笑话?我觉得这是一件很简单的事情,但我一直在努力想弄明白。

最接近的方法是用requires替换imports,并将它们移动到测试/函数中。这两件事都不是我想做的。

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

如果dependency.js中的函数是默认导出,我希望整个过程都能正常工作。然而,我知道在Jasmine中刺探默认导出不起作用(或者至少我永远无法让它起作用),所以我也不抱希望在开玩笑的时候这是可能的。


共3个答案

匿名用户

我已经能够通过使用涉及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(),因为它支持轻松地恢复其原始值,从而避免前面提到的“泄漏”。

匿名用户

你得模仿模块,自己设置间谍:

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

匿名用户

要使用jest模拟ES6依赖项模块默认导出:

import myModule from '../myModule';
import dependency from '../dependency';

jest.mock('../dependency');

// If necessary, you can place a mock implementation like this:
dependency.mockImplementation(() => 42);

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

    expect(dependency).toHaveBeenCalledTimes(1);
    expect(dependency).toHaveBeenCalledWith(4);
  });
});

其他选择对我的案子都不起作用。