简体   繁体   English

如何模拟用 jest.mock 模拟的类的实例方法?

[英]How to mock instance methods of a class mocked with jest.mock?

How can the instance methods be mocked for a class that is being mocked with jest.mock ?如何为使用jest.mock的类模拟实例方法?

For example, a class Logger is mocked:例如,一个类Logger被模拟:

import Person from "./Person";
import Logger from "./Logger";

jest.mock("./Logger");

describe("Person", () => {
  it("calls Logger.method1() on instantiation", () => {
    Logger.method1.mockImplementation(() => {}) // This fails as `method1` is an instance method but how can the instance method be mocked here?
    new Person();
    
    expect(Logger.method1).toHaveBeenCalled();
  });
});

Automatic Mocking自动模拟

Calling jest.mock automatically mocks all the exports from the module being mocked unless a manual mock is specified using the __mocks__ directory.调用jest.mock自动模拟来自被模拟模块的所有导出,除非使用__mocks__目录指定手动模拟。

So, this line jest.mock("./Logger") has automatically replaced the Logger constructor and all of it's methods with mock functions allowing us to test how these functions behave.所以,这行jest.mock("./Logger")已经自动替换了Logger构造函数和它的所有方法与模拟函数允许我们测试这些函数的行为方式。

And the information related to the instances created by Logger is saved in Logger.mock.instances , so we can use this to test if the methods are being called properly. Logger创建的实例相关信息保存在Logger.mock.instances中,因此我们可以使用它来测试方法是否被正确调用。

import Person from "./Person";
import Logger from "./Logger";

jest.mock("./Logger");

describe("Person", () => {
  it("calls method1 on instantiation", () => {
    const p = new Person();
    // Logger constructor should have been called
    expect(Logger).toHaveBeenCalled();
    
    const mockLoggerInstance = Logger.mock.instances[0];
    const mockMethod1 = mockLoggerInstance.method1;
    // method1 should have also been called
    expect(mockMethod1).toHaveBeenCalled();
  });
});

Using Module Factory Parameter使用模块出厂参数

You can also explicitly provide a module factory by passing in a factory function as the second argument to jest.mock .您还可以通过将工厂函数作为第二个参数传递给jest.mock来显式提供模块工厂。 So, now the provided module factory would be used instead of Jest's automocking feature.因此,现在将使用提供的模块工厂来代替 Jest 的自动模拟功能。 Refer the docs for more information.有关更多信息,请参阅文档

import Person from "./Person";
import Logger from "./Logger";

const mockMethod1 = jest.fn();
jest.mock("./Logger", () =>
  jest.fn().mockImplementation(() => ({
    method1: mockMethod1,
  }))
);

describe("Person", () => {
  it("calls method1 on instantiation", () => {
    const p = new Person();
    // Logger constructor should have been called
    expect(Logger).toHaveBeenCalled();
    // method1 should have also been called
    expect(mockMethod1).toHaveBeenCalled();
  });
});

Note: jest.mock() calls are hoisted, so you cannot first define a variable and then use it inside a factory function unless the variable is prefixed with mock .注意: jest.mock()调用被提升,所以你不能先定义一个变量然后在工厂函数中使用它,除非变量以mock为前缀。 And because of this we can access mockMethod1 inside the factory.正因为如此,我们可以访问工厂内部的mockMethod1

Manual Mock手动模拟

You can achieve a similar behavior to module factory function by creating a manual mock located at __mocks__/Logger.js .您可以通过创建位于__mocks__/Logger.js的手动模拟来实现与模块工厂功能类似的行为。 And now this mock implementation can be used across test files by simply calling jest.mock .现在这个模拟实现可以通过简单地调用jest.mock来跨测试文件使用。

// __mocks__/Logger.js
const mockMethod1 = jest.fn();
const mockLogger = jest.fn(() => ({
  method1: mockMethod1,
}));

Usage is similar to the module factory function but you now also have to import the mocked method in your test.用法类似于模块工厂函数,但您现在还必须在测试中导入模拟方法。

Note: You still need to use the original module path, don't include __mocks__ .注意:您仍然需要使用原始模块路径,不要包含__mocks__

import Person from "./Person";
import Logger, { mockMethod1 } from "./Logger";

jest.mock("./Logger");

describe("Person", () => {
  it("calls method1 on instantiation", () => {
    const p = new Person();
    // Logger constructor should have been called
    expect(Logger).toHaveBeenCalled();
    // method1 should have also been called
    expect(mockMethod1).toHaveBeenCalled();
  });
});

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

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