模拟静态问题 class 属性

Problems mocking static class property

我有一个 class 应该记录一些东西。记录器是这样定义的。

export class Logger {
  public static client = ClientStrategy.create();

  public async logSth(msg: string) {
    params = {"testThing": msg};
    await Logger.client.updateItem(params);
}
export class ClientStrategy {
  public static create() {
    return new DatabaseClient(); // not important here just a factory, with a method updateItem
  }
}

我正试图在开玩笑的测试中嘲笑它。我正在尝试模拟此客户端策略并为此创建一个方法。但它并没有像我预期的那样工作。

jest.mock("./ClientStrategy");
const mockClientStrategy = jest.mocked(ClientStrategy, false);

describe("Logger", () => {

    beforeEach(() => {
    jest.spyOn(<any>mockDatabaseClientStrategy, "create").mockImplementation(() => {
      return {
        updateItem: () => {
          return {}
        } 
      };
    });
  });

   
  it("should log sth", async () => {
    const response = await Logger.logSth("testMsg");
    expect(response).not.tobeUndefined();
  });
});

但我无法读取未定义的 属性“logSth”。你能帮我我在这里做错了什么吗?我认为我的模拟应该可以正常工作,但不幸的是我为此未定义。

jest.mock()jest.spyOn() 都可以。但是没有必要将它们一起用于您的情况。因此,让我们使用 jest.spyOn() 来解决您的问题。

由于 ClientStrategy.create 将在您导入 Logger class 时执行,您需要在导入 Logger 之前添加对 ClientStrategy.create 的监视 class.

此外,logSth 方法是一个实例方法,而不是 class 方法。

例如

Logger.ts:

import { ClientStrategy } from './ClientStrategy';

console.log('ClientStrategy.create: ', ClientStrategy.create);
export class Logger {
  public static client = ClientStrategy.create();

  public async logSth(msg: string) {
    const params = { testThing: msg };
    return Logger.client.updateItem(params);
  }
}

Logger.test.ts:

import { ClientStrategy } from './ClientStrategy';
// import { Logger } from './Logger';

describe('Logger', () => {
  let mockClient;
  let Logger: typeof import('./Logger').Logger;
  beforeEach(async () => {
    mockClient = {
      updateItem: jest.fn(),
    };
    jest.spyOn(ClientStrategy, 'create').mockReturnValue(mockClient);
    Logger = await import('./Logger').then((m) => m.Logger);
  });
  afterEach(() => {
    jest.restoreAllMocks();
  });

  it('should log sth', async () => {
    mockClient.updateItem.mockResolvedValueOnce('fake value');
    const logger = new Logger();
    const response = await logger.logSth('testMsg');
    expect(response).toEqual('fake value');
  });
});

ClientStrategy.ts:

export class ClientStrategy {
  public static create() {
    return { updateItem: async (params) => 'real value' };
  }
}

测试结果:

 PASS  Whosebug/71938329/Logger.test.ts
  Logger
    ✓ should log sth (22 ms)

  console.log
    ClientStrategy.create:  [Function: mockConstructor] {
      _isMockFunction: true,
      getMockImplementation: [Function (anonymous)],
      mock: [Getter/Setter],
      mockClear: [Function (anonymous)],
      mockReset: [Function (anonymous)],
      mockRestore: [Function (anonymous)],
      mockReturnValueOnce: [Function (anonymous)],
      mockResolvedValueOnce: [Function (anonymous)],
      mockRejectedValueOnce: [Function (anonymous)],
      mockReturnValue: [Function (anonymous)],
      mockResolvedValue: [Function (anonymous)],
      mockRejectedValue: [Function (anonymous)],
      mockImplementationOnce: [Function (anonymous)],
      mockImplementation: [Function (anonymous)],
      mockReturnThis: [Function (anonymous)],
      mockName: [Function (anonymous)],
      getMockName: [Function (anonymous)]
    }

      at Object.<anonymous> (Whosebug/71938329/Logger.ts:3:9)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        2.57 s, estimated 11 s

您可以取消注释import { Logger } from './Logger'; 语句并注释import() 来检查日志。您将看到未模拟的 ClientStrategy.create 方法:

console.log
    ClientStrategy.create:  [Function: create]