无法将 jest.mock 用于 TypeScript 类

Ell*_*lis 6 javascript unit-testing typescript jestjs

我试图按照Jest 文档中的ES6 Class Mocks页面来测试 TypeScript class 上的方法Consumer。这个类实例化一个Provider对象并调用它的方法,所以我想模拟这个Provider类。

目录结构:

.
??? __tests__
?   ??? consumers
?       ??? Consumer.test.ts
??? js
    ??? providers
    ?   ??? provider.ts
    ??? consumers
        ??? Consumer.ts
Run Code Online (Sandbox Code Playgroud)

provider.ts

export class Provider {
    constructor() {}

    public action(params) {
        // do some stuff that we need to mock
        return something;
    }
}
Run Code Online (Sandbox Code Playgroud)

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'
    }
}
Run Code Online (Sandbox Code Playgroud)

我的第一次尝试是使用默认的“自动模拟”:

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

Run Code Online (Sandbox Code Playgroud)

这证明我可以用模拟替换真正的实现,但我需要确保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();
});
Run Code Online (Sandbox Code Playgroud)

无论我如何尝试更改模拟,我都找不到可以让我在Consumer测试中正常使用的解决方案。我宁愿避免创建“手动模拟”,这样我就可以保持代码库更干净并在测试之间改变模拟实现。

Ell*_*lis 1

我似乎通过确保要模拟的依赖项是默认导出来解决这个问题:

Provider.ts:

export default class Provider {}
Run Code Online (Sandbox Code Playgroud)

Consumer.ts, Consumer.test.ts:

import Provider from "../providers/provider";
Run Code Online (Sandbox Code Playgroud)

我相信这是因为jest.mock()目标是一个模块,并且provider是一个Provider 内部定义了类的模块。如果该模块中没有默认导出,则模拟的确切目标是不明确的。通过将类设置为默认导出,Jest 知道将其用作模拟的目标。