简体   繁体   English

无法将jest.mock用于TypeScript类

[英]Unable to use jest.mock for TypeScript class

I've attempted to follow the ES6 Class Mocks page in the Jest documentation to test a method on a TypeScript class Consumer . 我试图按照Jest文档中的ES6类提示页面来测试TypeScript类Consumer上的方法。 This class instantiates a Provider object and calls methods on it, so I would like to mock the Provider class. 此类实例化Provider对象并在其上调用方法,因此我想模拟Provider类。

Directory structure: 目录结构:

.
├── __tests__
│   └── consumers
│       └── Consumer.test.ts
└── js
    ├── providers
    │   └── provider.ts
    └── consumers
        └── Consumer.ts

provider.ts : provider.ts

export class Provider {
    constructor() {}

    public action(params) {
        // do some stuff that we need to mock
        return something;
    }
}

Consumer.ts : Consumer.ts

import {Provider} from "../providers/provider";

export class Consumer {
    private provider: Provider;

    constructor() {
        this.provider = new Provider();
    }

    public doSomething() {
        const result = this.provider.action(params);
        // do something with 'result'
    }
}

My first attempt was with a default "automatic mock": 我的第一次尝试是使用默认的“自动模拟”:

Consumer.test.ts : Consumer.test.ts

import {Consumer} from "../../js/consumers/Consumer";

jest.mock("../../js/providers/provider");

test("Consumer doSomething", () => {
    // a mock Provider will be instantiated in Consumer's ctor:
    const consumer = new Consumer();

    // however, Provider.action() will return undefined within doSomething()
    consumer.doSomething();
});

This proves that I can replace the real implementation with a mock, but I need to ensure that Provider.action() returns a value, so next I tried: 这证明我可以用模拟代替真正的实现,但是我需要确保Provider.action()返回一个值,因此接下来我尝试了:

// at some point we can make this return something, but first check it works
const mockAction = jest.fn();
jest.mock("../../js/providers/provider", () => {
  return jest.fn().mockImplementation(() => {
    return {action: mockAction};
  });
});

test("Consumer doSomething", () => {
    // throws TypeError: provider_1.Provider is not a constructor
    const consumer = new Consumer();

    consumer.doSomething();
});

No matter how I've tried changing the mock, I can't find a solution which allows me to use Consumer as normal from my test. 无论我如何尝试更改模拟,都找不到能够让我从测试中正常使用Consumer的解决方案。 I'd rather avoid creating "manual mocks" so I can keep the codebase cleaner and vary the mock implementation between tests. 我宁愿避免创建“手动模拟”,这样我可以保持代码库更清洁,并在测试之间更改模拟实现。

I seem to have solved this by ensuring that the dependency to be mocked is a default export: 我似乎已经通过确保要模拟的依赖项是默认导出来解决了这一问题:

Provider.ts : Provider.ts

export default class Provider {}

Consumer.ts , Consumer.test.ts : Consumer.tsConsumer.test.ts

import Provider from "../providers/provider";

I believe this is because jest.mock() targets a module and provider is a module with a class Provider defined inside it . 我相信这是因为jest.mock()目标是一个模块provider是一个在其中定义Provider类的模块。 Without a default export in that module, the exact target for the mock is ambiguous. 在该模块中没有默认导出,模拟的确切目标是不确定的。 By making the class a default export, Jest knows to use it as the target for the mock. 通过将类设置为默认导出,Jest知道将其用作模拟的目标。

You don't have to use a default export here. 您无需在此处使用默认导出。 When using named exports you need to create a mock that matches the "shape" of your module. 使用命名导出时,您需要创建一个与模块“形状”匹配的模拟。 So in your case: 因此,在您的情况下:

const mockAction = jest.fn();
jest.mock("../../js/providers/provider", () => ({
 Provider: jest.fn().mockImplementation(() => ({
    action: mockAction
  }))
));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM