我想测试我的一个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);
  });
});

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

作为奖励,我希望在dependency.js中的函数是默认导出时使整个事情正常工作。但是,我知道监视默认导出在Jasmine中不起作用(或者至少我永远无法让它起作用),所以我对在Jest中也能做到这一点不抱希望。


当前回答

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

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

其他回答

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

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

编辑:几年过去了,这样做已经不是正确的方式了(可能从来都不是,我的错)。

修改导入的模块非常麻烦,可能会导致副作用,比如根据执行顺序通过或失败的测试。

出于历史的考虑,我将这个答案保留原貌,但你真的应该开个玩笑。间谍或玩笑,嘲弄。详情请参考笑话文档或本页的其他答案。

原答案如下:


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

对于命名的导出:

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

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

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

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

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

我用另一种方法解决了这个问题。假设你有依赖项。js

export const myFunction = () => { }

我在它之外创建了一个dependency .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();

})