ts-jest:模拟内部模块

时间:2021-06-24 11:56:35

标签: typescript unit-testing jestjs ts-jest

我有以下 .ts 模块

import client from './client';

export default class DefaultRequest implements IRequest {
    make(req: Request): Promise<Response> {
        return new Promise<Response>((resolve, reject) => {
            client.post(req, (error: Error | null, res: Response) => {
                if (error) {
                    return reject(error);
                } else {
                    return resolve(res);
                }
            });
        });
    }
}

我正在尝试使用 ts-jest 为此类编写单元测试,以便模拟 client(并返回一些有效的 Response)。

这是我的做法:

import {mocked} from 'ts-jest/utils';
import client from './client';
import DefaultRequest from './request'

const mockedClient = mocked(client, true);
const testRequest = new DefaultRequest();

jest.mock('./client', () => {
  return {
    RestClient: jest.fn().mockImplementation(() => {
      return {
        post: () => {return someValidResponse();},
      };
    })
  };
});

describe('My Tests', () => {

    it('Unit Test 1', async () => {
        let res: Response = await testRequest.make(buildReq());
    });
});

但是mockedClient 仍然没有被mock。这就是 ./client.ts 的样子:

import { RestClient } from '@rest/client';

export default new RestClient();

可以以这种方式模拟类 client 使用的内部 DefaultRequest 模块吗?

编辑: 我也试过jest.spyOn

const spiedMethod= jest.spyOn(client, 'post');
        const call: Request = new Request();
        const response: Response = await call.make(buildRequest());

        expect(spiedReleaseMethod).toHaveBeenCalled();
        expect(response.getResponsecode()).toBe(200);

它仍然调用原始方法而不是被监视的方法。

1 个答案:

答案 0 :(得分:1)

您正在测试依赖于 request.ts 模块的 client.ts 模块。因此,您需要模拟 client.ts 模块及其 post 方法而不是 @rest/client 包。

例如

request.ts

import client from './client';

interface IRequest {
  make(req: Request): Promise<Response>;
}

export default class DefaultRequest implements IRequest {
  make(req: Request): Promise<Response> {
    return new Promise<Response>((resolve, reject) => {
      client.post(req, (error: Error | null, res: Response) => {
        if (error) {
          return reject(error);
        } else {
          return resolve(res);
        }
      });
    });
  }
}

client.ts:(无论客户端使用什么包实现,只要模块暴露的接口相同即可)

export default {
  post(req, callback) {
    console.log('real implementation');
  },
};

request.test.ts

import { mocked } from 'ts-jest/utils';
import client from './client';
import DefaultRequest from './request';

jest.mock('./client');

const mockedClient = mocked(client);

describe('68115300', () => {
  afterAll(() => {
    jest.resetAllMocks();
  });
  it('should pass', () => {
    mockedClient.post.mockImplementationOnce((req, callback) => {
      callback(null, 'mocked response');
    });
    const testRequest = new DefaultRequest();
    testRequest.make(('req' as unknown) as Request);
    expect(mockedClient.post).toBeCalledWith('req', expect.any(Function));
  });
});

测试结果:

 PASS  examples/68115300/request.test.ts (12.448 s)
  68115300
    ✓ should pass (3 ms)

------------|---------|----------|---------|---------|-------------------
File        | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
------------|---------|----------|---------|---------|-------------------
All files   |   77.78 |       50 |      75 |   77.78 |                   
 client.ts  |      50 |      100 |       0 |      50 | 3                 
 request.ts |   85.71 |       50 |     100 |   85.71 | 12                
------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        14.61 s