【问题标题】:Jest: How to undo a global mock for certain tests in a file笑话:如何为文件中的某些测试撤消全局模拟
【发布时间】:2020-12-21 19:58:14
【问题描述】:

我想为某些测试模拟 Math.random,并将其原始实现用于其他测试。我怎样才能做到这一点?我读过有关使用 jest.doMockjest.dontMock 的信息,但在使用它们时遇到了一些问题,例如:

  • 我似乎需要require 才能使用doMockdontMock,但是 我的项目只使用 ES6 模块来导入模块
  • 这些函数在像Math 这样的全局模块中也存在问题。 尝试使用 jest.doMock("Math.random") 时出现错误, 结果Cannot find module 'Math' from 'app.test.js'

我的测试不一定需要使用doMockdontMock。它们似乎是我在笑话文档中能找到的最接近我想要实现的东西。但我对替代解决方案持开放态度。

我想在 app.js 中测试的函数...

export function getRandomId(max) {
    if (!Number.isInteger(max) || max <= 0) {
        throw new TypeError("Max is an invalid type");
    }
    return Math.floor(Math.random() * totalNumPeople) + 1;
}

在 app.test.js 里面...

describe("getRandomId", () => {
  const max = 10;
  Math.random = jest.fn();

  test("Minimum value for an ID is 1", () => {
      Math.mockImplementationOnce(() => 0);
      const id = app.getRandomId(max);
      expect(id).toBeGreaterThanOrEqual(1);
  });

  test("Error thrown for invalid argument", () => {
      // I want to use the original implementation of Math.random here
      expect(() => getRandomId("invalid")).toThrow();
  })
});

【问题讨论】:

标签: javascript jestjs


【解决方案1】:

试试这个:

describe("getRandomId", () => {
  const max = 10;
  let randomMock;

  beforeEach(() => {
    randomMock = jest.spyOn(global.Math, 'random');
  });

  test("Minimum value for an ID is 1", () => {
      randomMock.mockReturnValue(0);
      const id = getRandomId(max);
      expect(id).toBeGreaterThanOrEqual(1);
  });

  test("Error thrown for invalid argument", () => {
      // I want to use the original implementation of Math.random here
      randomMock.mockRestore(); // restores the original (non-mocked) implementation
      expect(() => getRandomId("invalid")).toThrow();
  })
});

【讨论】:

  • 谢谢,这很有帮助!但是,在第二个测试中使用 mockRestore 时,我注意到了奇怪的行为。出于好奇,我想看看Math.random 在恢复randomMock 后返回了什么。所以我放置了一个expect(randomMock).toHaveReturnedWith(20) 以使测试失败并查看Math.Random 实际返回的内容。奇怪的是,测试失败了,因为 Math.Random 根本没有被调用。
  • 如果我在第一个测试中使用mockReturnValueOnce(0) 并在第二个测试中将mockRestore 替换为mockClear,问题就解决了。结果显示Math.Random 以其原始实现被调用。你知道为什么mockRestore 导致Math.Random 没有被调用吗?
  • 它适用于您的修改的原因是mockReturnValueOnce(0),它将在第一次调用Math.random 后恢复模拟。恢复randomMock 只是意味着对Math.random() 的任何后续调用都不会被模拟。但randomMock 不再可用,因为它失去了与Math.random 的绑定
  • 您可以通过在两个测试中添加console.log(getRandomId(42) 来检查答案是否按预期工作(在第一个测试中的模拟之后和第二个测试中的恢复之后)。运行测试将始终在第一个测试中打印出 1,在第二种情况下打印出一个随机整数(在给定的边界内)。
  • 很高兴知道!我没有意识到randomMock 在调用mockRestore 后会失去与Math.Random 的绑定。在运行我的测试时,我也能够验证这种行为。谢谢你的解释。
猜你喜欢
  • 2019-04-13
  • 2022-08-19
  • 2022-12-22
  • 2021-10-30
  • 2019-03-26
  • 2016-08-30
  • 1970-01-01
  • 2018-07-15
  • 1970-01-01
相关资源
最近更新 更多