如何使用Jest模拟命名的导出构造函数和外部库的函数?

时间:2020-06-24 16:33:22

标签: javascript unit-testing testing mocking jestjs

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

例如,当我从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不是函数

这是我要测试的文件:

const limiter = new RateLimiterRedis(opts);

我还尝试了doMocking命名的出口本身(因为模拟吊装本身一直到顶部)没有成功

我的问题归结为当一个类是外部库的命名导出时,如何模拟一个类的构造函数并且该类具有开玩笑的功能?

编辑:
模拟获取定义:

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

这使我相信我可以使用模拟获取

1 个答案:

答案 0 :(得分:0)

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

“我尝试过”代码段是错误的,因为它使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
      })
    };
  });

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

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