【问题标题】:How do you mock a named exports constructor and functions of an external library with Jest?如何使用 Jest 模拟外部库的命名导出构造函数和函数?
【发布时间】:2020-06-24 16:33:22
【问题描述】:

我看到过类似的问题,但我在文档或 stackoverflow 中没有看到任何描述我正在尝试做的事情。我是 javascript 新手,刚开始使用 jest,我已经阅读了 jest 文档,但我还没有看到模拟外部库的命名导出的示例。我试图模拟的库是速率限制器灵活的。我想模拟命名的导出 RateLimiterRedis。我需要模拟几个 RateLimiterRedis 函数,包括 get、consume 和 delete。

例如,当我从 redis 模拟一个函数时,我所要做的就是:

import redis from 'redis';
jest.mock('redis', () => {
    return { createClient: jest.fn()};
});

当我尝试时:

jest.mock('rate-limiter-flexible', () => {
    return jest.fn().mockImplementation(() => {
        return { RateLimiterRedis: { get: mockGet } }
    });
});

我得到:TypeError: _rateLimiterFlexible.RateLimiterRedis 不是构造函数

当我尝试时:

jest.mock('rate-limiter-flexible', () => {
    return { RateLimiterRedis: () => {}}
});

我得到:TypeError:limiter.get 不是函数
所以它可以识别构造函数,但我需要添加函数。

我试过了:

jest.mock('rate-limiter-flexible', () => {
    return { RateLimiterRedis: () => {
        return jest.fn().mockImplementation(() => {
            return {
                get: mockGet
            }
        })
    },
            }
});

这也给出:TypeError:limiter.get is not a function

这是在我要测试的文件中:

const limiter = new RateLimiterRedis(opts);

我也尝试过 doMocking 命名的导出本身(因为模拟将自己提升到顶部)但没有成功

我的问题归结为,当该类是外部库的命名导出时,我如何模拟一个类的构造函数以及该类的函数?

编辑:
mockGets 定义:

const mockIpAndUrl ={
    consumedPoints:1
};

const mockGet = jest.fn().mockImplementation(() => {
    return mockIpAndUrl;
})

这不起作用:

const mockIpAndUrl ={
    consumedPoints:1
};

const mockGet = jest.fn().mockImplementation(() => {
    return mockIpAndUrl;
})

jest.mock('rate-limiter-flexible', () => {
    return{
        RateLimiterRedis: jest.fn().mockImplementation(() => {
            return { get : mockGet};
        })
    }
});

TypeError:limiter.get 不是函数

但是,这样做:

jest.mock('rate-limiter-flexible', () => {
    return{
        RateLimiterRedis: jest.fn().mockImplementation(() => {
            return { get : jest.fn().mockImplementation(() => {
                return mockIpAndUrl;
            })};
        })
    }
});

这是我所指的文档: https://jestjs.io/docs/en/es6-class-mocks#calling-jestmockdocsenjest-objectjestmockmodulename-factory-options-with-the-module-factory-parameter

这让我相信我可以使用 mockGet

【问题讨论】:

    标签: javascript unit-testing testing mocking jestjs


    【解决方案1】:

    rate-limiter-flexible 的导出是一个对象,它应该具有RateLimiterRedis 函数,该函数返回一个具有get 方法的实例。

    “我试过”sn-p 是错误的,因为它使RateLimiterRedis 函数返回另一个函数,而RateLimiterRedis 本身不是间谍,因此无法断言。

    应该是:

      jest.mock('rate-limiter-flexible', () => {
        return {
          RateLimiterRedis: jest.fn().mockImplementation(() => ({
            get: mockGet
          })
        };
      });
    

    如果RateLimiterRedis 在顶级导入中被实例化,mockGet 在被模拟访问之前不能被赋值。它可以作为模拟模块的一部分导出:

      jest.mock('rate-limiter-flexible', () => {
        const mockRateLimiterRedisGet = jest.fn();
        return {
          mockRateLimiterRedisGet,
          RateLimiterRedis: jest.fn().mockImplementation(() => ({
            get: mockRateLimiterRedisGet
          })
        };
      });
    

    这允许在测试中从rate-limiter-flexible 导入mockRateLimiterRedisGet 并用于动态模拟值和断言:

    mockRateLimiterRedisGet.mockReturnValue(...);
    ...
    expect(mockRateLimiterRedisGet).toBeCalled();
    

    【讨论】:

    • 谢谢!这就是应该这样做的方式。我注意到的是,我已经正确定义了 mockGet,但由于某种原因,mockGet 不会解析为函数。我必须得到:jest.fn().mockImplementation(() => { //我的模拟实现}),即使这正是我设置的 mockGet 等于。我知道 mock 将自己提升到顶部,但我认为任何以 mock 开头的东西都可以工作,我记得在 jests 文档中读过这一点
    • 该问题不包含 mockGet 定义。它与模拟吊装无关,而是与进口吊装有关。这将发生在您需要 RateLimiterRedis 被模拟的模块被立即导入。如果是这种情况,您可以尝试像以前一样将mockReturnValue(...) 替换为mockImplementation(() => ({ get: mockGet })),这将使mockGet 延迟访问。如果在导入时实例化 RateLimiterRedis,这将不起作用。
    • 这就是我说的:jestjs.io/docs/en/…
    • 是的,这是一个众所周知的问题。正如我所提到的,mockImplementation 而不是 mockReturnValue 可能会有所帮助。之后是否可以使用 mockGet 取决于 new RateLimiterRedis 何时发生。 mockGet 并不总是必要的,但如果您需要动态更改返回值,它是必要的,它使断言更容易,expect(mockGet).toBeCalled() 而不是expect(RateLimiterRedis.mock.results[0].value.get).toBeCalled()
    • 如果您需要使用 mockGet,请将 file-that-uses-rate-limiter-flexible 导入到测试中并将其更改为 require
    猜你喜欢
    • 2020-01-08
    • 2018-02-23
    • 2021-04-05
    • 1970-01-01
    • 2021-07-17
    • 2023-03-09
    • 2020-05-06
    • 2016-04-03
    • 1970-01-01
    相关资源
    最近更新 更多