jest.mock与命名的出口如何监视

时间:2019-11-25 03:07:42

标签: mocking jestjs

让我们说我在文件customer.ts中有以下命名的导出

export const saveDetails = ()=>{}
export const loadDetails = ()=>{}

假设我正在其他文件中使用它

import {saveDetails, loadDetails} from './customer.ts'

我想用自定义实现模拟'./customer.ts'。为此,我使用以下代码

const mockSaveDetails = jest.fn().mockImplementation(() => {});
jest.mock('./customer.ts', () => {
  return {
    saveDetails: mockSaveDetails
  };
});

现在,当我运行此代码时,出现以下错误

  

ReferenceError:初始化前无法访问'mockSaveDetails'

根据https://jestjs.io/docs/en/es6-class-mocks上的文档,我了解到该模拟被提升到顶部,并且例外情况是该变量的前缀为mock。因此,根据文档,这应该正确吗?如果不是,那么提供带有特定参数的模拟模仿实现并监视这些实现的替代方法(例如,请参阅对saveDetails的多次调用)。

4 个答案:

答案 0 :(得分:4)

ReferenceError:初始化前无法访问'mockSaveDetails'

模拟设置必须是文件中的第一件事,即使在import之前也是如此。然后mockSaveDetails将被识别。

如文档所述,它与提升模拟功能有关,但是对于TypeScript来说,这并没有按文档记录完成,因此我们需要一点帮助...

答案 1 :(得分:0)

这是解决方案:

index.ts

import { saveDetails, loadDetails } from "./customer";

export function main() {
  saveDetails();
  loadDetails();
}

customer.ts

export const saveDetails = () => {
  console.log("real save details");
};
export const loadDetails = () => {
  console.log("real load details");
};

index.spec.ts

import { main } from "./";
import { saveDetails, loadDetails } from "./customer";

jest.mock("./customer.ts", () => {
  return {
    saveDetails: jest.fn(),
    loadDetails: jest.fn()
  };
});

describe("main", () => {
  it("should mock correctly", () => {
    main();
    expect(saveDetails).toBeCalledTimes(1);
    expect(loadDetails).toBeCalledTimes(1);
  });
});

覆盖率100%的单元测试结果:

PASS  src/stackoverflow/59024742/index.spec.ts
  main
    ✓ should mock correctly (5ms)

----------|----------|----------|----------|----------|-------------------|
File      |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
----------|----------|----------|----------|----------|-------------------|
All files |      100 |      100 |      100 |      100 |                   |
 index.ts |      100 |      100 |      100 |      100 |                   |
----------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        5.626s, estimated 9s

源代码:https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/59024742

答案 2 :(得分:0)

如果要为其中一个模拟函数提供实现,则此答案无效。

我发现的唯一解决方案是更改import语句,然后对此使用间谍程序。

customer.ts

const saveDetails = () => {
  console.log("real save details");
};
const loadDetails = () => {
  console.log("real load details");
};

export { saveDetails, loadDetails }

index.ts

import { saveDetails, loadDetails } from "./customer";

export function main() {
  saveDetails();
  loadDetails();
}

index.spec.ts

import { main } from ".";
import * as customer from "./customer";

describe("main", () => {
  it("should mock correctly", () => {
    const detailsSpy = jest.spyOn(customer, 'saveDetails')
      .mockImplementation(() => {return {}});
    const loadSpy = jest.spyOn(customer, 'loadDetails')
      .mockImplementation(() => {return {}});

    main();
    expect(detailsSpy).toBeCalledTimes(1);
    expect(loadSpy).toBeCalledTimes(1);
  });
});

答案 3 :(得分:0)

如果你们都想模拟一个命名函数并提供一个实现,你就不需要 import * as 语法。您可以执行以下操作:

// import the named module
import { useWalkthroughAnimations } from '../hooks/useWalkthroughAnimations';

// mock the file and its named export
jest.mock('../hooks/useWalkthroughAnimations', () => ({
  useWalkthroughAnimations: jest.fn()
}));

// do whatever you need to do with your mocked function
useWalkthroughAnimations.mockReturnValue({ pageStyles, goToNextPage, page });