【问题标题】:Jest - mock a named class-export in typescriptJest - 在打字稿中模拟一个命名的类导出
【发布时间】:2022-05-12 19:54:09
【问题描述】:

我有一个导出几个类的节点模块,其中一个是Client,我用它来创建一个客户端(有几个 API 作为方法)。

我正在尝试使用 Jest 测试我的模块,该模块将此节点模块用作依赖项。但是,我无法成功模拟 Client 类中的一种方法(比如 search())。

这是我对myModule 的规范:

//index.spec.ts
import * as nock from 'nock';
import * as externalModule from 'node-module-name';
import { createClient } from './../../src/myModule';
describe(() => {
  beforeAll(() => {
    nock.disableNetConnect();
  });
  it('test search method in my module', () => {
    jest.mock('node-module-name');

    const mockedClient = <jest.Mock<externalModule.Client>>externalModule.Client;

    const myClient = createClient({/*params*/}); //returns instance of Client class present in node module by executing Client() constructor
    myClient.searchByName('abc'); //calls search API - I need to track calls to this API

    expect(mockedClient).toHaveBeenCalled();
    expect(mockedClient.prototype.search).toHaveBeenCalledWith('abc');
  });
});

然而,这根本不会创建模拟,并会触发一个 nock 错误,因为搜索 API 会尝试连接到 url(通过参数给出)。

我也尝试过像下面这样模拟 Client 类。虽然成功地为 Client 类和搜索 API 创建了一个模拟(验证 search() 也通过控制台日志模拟),但当我尝试检查是否已调用 search() 时,它给了我一个错误。

externalModule.Client = jest.fn(() => { return { search: jest.fn(() => Promise.resolve('some response')) } });
//creates the mock successfully, but not sure how to track calls to 'search' property

const client = myModule.createClient(/*params*/);
client.searchByName('abc');

expect(externalModule.Client).toHaveBeenCalled(); //Successful
expect(externalModule.Client.prototype.search).toHaveBeenCalled(); //returns error saying "jest.fn() value must be a mock function or spy, Received: undefined"

我不确定我做错了什么。提前谢谢你。

【问题讨论】:

    标签: javascript node.js typescript unit-testing jestjs


    【解决方案1】:

    模拟整个模块

    尝试将jest.mock 移动到文件顶部

    //index.spec.ts
    const search = jest.fn();
    jest.mock('node-module-name', () => ({
      Client: jest.fn(() => ({ search }))
    }));
    import * as nock from 'nock';
    import * as externalModule from 'node-module-name';
    import { createClient } from './../../src/myModule';
    describe(() => {
      beforeAll(() => {
        nock.disableNetConnect();
      });
      it('test search method in my module', () => {
        const myClient = createClient({/*params*/});
        myClient.searchByName('abc'); 
    
        expect(externalModule.Client).toHaveBeenCalled();
        expect(search).toHaveBeenCalledWith('abc');
        externalModule.Client.mockClear();
        search.mockClear();
      });
    });
    

    仅模拟客户端

    创建search 常量并跟踪它。

    const search = jest.fn();
    externalModule.Client = jest.fn(() => ({ search }));
    
    const client = myModule.createClient(/*params*/);
    client.searchByName('abc');
    
    expect(externalModule.Client).toHaveBeenCalled();
    expect(search).toHaveBeenCalled();
    

    【讨论】:

    • 谢谢。这对我有用。那么有没有办法使用jest.mock('node-module-name') 来做到这一点?如果我在myModule 中使用这个类的许多(甚至是嵌套的)函数怎么办?我应该对这些嵌套函数中的每一个进行持续模拟还是有直接的方法?
    • 有办法的。尝试将 jest.mock 移动到文件顶部。请参阅我编辑的答案。让我知道它是否有效。
    【解决方案2】:

    这就是我嘲笑它的方式。我不得不更改命名并删除一些代码以避免暴露原始源代码。

    jest.mock('../foo-client', () => {
      return { FooClient: () => ({ post: mockPost }) }
    })
    

    完整代码。

    // foo-client.ts
    
    export class FooClient {
        constructor(private config: any)
        post() {}
    }
    
    // foo-service.ts
    
    import { FooClient } from './foo-client'
    
    export class FooLabelService {
        private client: FooClient
        constructor() {
            this.client = new FooClient()
        }
    
        createPost() {
            return this.client.post()
        }
    }
    
    // foo-service-test.ts
    
    import { FooService } from '../foo-service'
    
    const mockPost = jest.fn()
    jest.mock('../foo-client', () => {
      return { FooClient: () => ({ post: mockPost }) }
    })
    
    describe('FooService', () => {
      let fooService: FooService
    
      beforeEach(() => {
        jest.resetAllMocks()
        fooService = new FooService()
      })
    
      it('something should happened', () => {
        mockPost.mockResolvedValue()
        fooService.createPost()
      })
    })
    

    【讨论】:

      猜你喜欢
      • 2021-06-11
      • 2019-10-19
      • 2022-07-09
      • 2018-09-16
      • 1970-01-01
      • 2021-04-14
      • 2020-04-13
      • 1970-01-01
      • 2018-03-27
      相关资源
      最近更新 更多