开玩笑如何模拟打字稿类,但仅在 1 个测试中交替某些方法行为,而不在其他测试中修改模拟

分享于2022年07月17日 javascript jestjs ts-jest typescript unit-testing 问答
【问题标题】:开玩笑如何模拟打字稿类,但仅在 1 个测试中交替某些方法行为,而不在其他测试中修改模拟(Jest how to mock a typescript class but alternate some method behavior in only 1 test and not modify mock in others)
【发布时间】:2022-01-27 04:37:33
【问题描述】:

我有一个打字稿类 userInfo.ts:

export class UserInfo {
  public getName() {
    return "I am real name";
  }
}

我在 mocks 文件夹中有一个模拟类 userInfo.ts:

export class UserInfo {
  public getName() {
    return "I am fake name";
  }
}

我有一个客户:

import { UserInfo } from "./userInfo";
export class Client {

  public functionToTest() {
    let validation = new UserInfo();
    return validation.getName();
  }

}

最后我想对此进行两次测试,在第一个中我想只为这个测试覆盖 getName 模拟,在第二个中我想有模拟的类行为:

import { Client } from "./client";
import { UserInfo } from "./userInfo";

jest.mock("./userInfo");
const userInfoMocked = UserInfo as jest.MockedClass; // I tried with this but with no success

describe("Client", () => {

  it("should get Name", () => {
    let client = new Client();
    // UserInfo.prototype.getName = jest.fn().mockImplementationOnce(() => {
    //   return "Something weird happened";
    // });
    userInfoMocked.prototype.getName = jest.fn().mockImplementationOnce(() => {
      return "something weird happend";
    });

    // this is not working either
    // Property 'getName' does not exist on type 'MockedClass'.
    // userInfoMocked.getName = jest.fn().mockImplementationOnce(() => {
    //   return "something weird happend";
    // });

    let text = client.functionToTest();
    expect(text).toBe('something weird happend'); 
    let text2 = client.functionToTest();
    expect(text2).toBe('I am fake name'); // I get undefined (I overwrote prototype!)
  });

  it('should get fake name now', () => {
    let client = new Client();
    let text3 = client.functionToTest();
    expect(text3).toBe('I am fake name'); // I get undefined

  });
});

我很惊讶这种常见的(我认为)功能无法实现?如何在这方面取得成功?这甚至可能吗?

  • 你为什么不在第二次测试中 jest.fn().mockImplementationOnce?

【解决方案1】:

您可以为模拟分配一个默认实现:

import userInfo from "./userInfo"
jest.mock("./userInfo", () => ({
  getName: jest.fn(() => 'John Doe'),
}));

而且每次你​​想覆盖实现时:

userInfo.getName.mockImplementation(() => jest.fn().mockReturnValue('another value'));

  • 覆盖时它不起作用:“typeof UserInfo”类型上不存在属性“mockImplementation”
  • 我已经更新了覆盖示例