【问题标题】:JavaScript - mocking console in Jest / mock "was not called"JavaScript - Jest / mock 中的模拟控制台“未被调用”
【发布时间】:2019-04-21 21:51:42
【问题描述】:

我正在尝试模拟 console.info,我知道它会在导入的函数运行时被调用。该函数完全由单个fetch 组成,当不在生产环境中运行时,它使用console.info 报告请求和响应。

在问题Jest. How to mock console when it is used by a third-party-library? 中,评分最高的答案建议覆盖global.console,所以我使用jest.spyOn 进行尝试:

import * as ourModule from "../src/ourModule";

test("Thing", () => {
    // Tested function requires this. Including it here in case it's causing
    // something quirky that readers of this question may know about
    global.fetch = require("jest-fetch-mock");

    const mockInfo = jest.spyOn(global.console, "info").mockImplementation(
        () => { console.error("mockInfo") }
    );

    ourModule.functionBeingTested("test");
    expect(mockInfo).toHaveBeenCalled();
}

正如预期的那样,输出包含一个“mockInfo”实例。但是,然后使用 toHaveBeenCalled() 进行测试失败。

expect(jest.fn()).toHaveBeenCalled()

Expected mock function to have been called, but it was not called.

  40 |
  41 |     ourModule.functionBeingTested("test");
> 42 |     expect(mockInfo).toHaveBeenCalled();
     |                      ^
  43 | 

  at Object.toHaveBeenCalled (__tests__/basic.test.js:42:22)

console.error __tests__/basic.test.js:38
  mockInfo

我已经尝试将spyOn 移动到模块加载之前,正如答案中的一个 cmets 所建议的那样,结果没有差异。我在这里错过了什么?

这是有问题的函数:

function functionBeingTested(value) {
    const fetchData = {
        something: value
    };

    fetch("https://example.com/api", {
        method: "POST",
        mode:   "cors",
        body:   JSON.stringify(fetchData),
    })
        .then( response => {
            if (response.ok) {
                if (MODE != "production") {
                    console.info(fetchData);
                    console.info(response);
                }
            } else {
                console.error(`${response.status}: ${response.statusText}`);
            }
        })
        .catch( error => {
            console.error(error);
        });
}

【问题讨论】:

  • 你调用的第三方库函数是什么?
  • @brian-lives-outdoors:我不是,那是另一个问题。
  • 你能展示一下ourModule.functionBeingTested的作用吗?
  • 它获取一个 URL - 我已将其添加到问题中。

标签: javascript unit-testing asynchronous mocking jestjs


【解决方案1】:

问题

console.info 在一个 Promise 回调中被调用,该回调在 ourModule.functionBeingTested 返回和 expect 运行时尚未执行。

解决方案

确保调用console.info 的Promise 回调在运行expect 之前已经运行。

最简单的方法是从ourModule.functionBeingTested返回Promise

function functionBeingTested(value) {
  const fetchData = {
    something: value
  };

  return fetch("https://example.com/api", {  // return the Promise
    method: "POST",
    mode: "cors",
    body: JSON.stringify(fetchData),
  })
    .then(response => {
      if (response.ok) {
        if (MODE != "production") {
          console.info(fetchData);
          console.info(response);
        }
      } else {
        console.error(`${response.status}: ${response.statusText}`);
      }
    })
    .catch(error => {
      console.error(error);
    });
}

...并在断言之前等待它解决:

test("Thing", async () => {  // use an async test function...
  // Tested function requires this. Including it here in case it's causing
  // something quirky that readers of this question may know about
  global.fetch = require("jest-fetch-mock");

  const mockInfo = jest.spyOn(global.console, "info").mockImplementation(
      () => { console.error("mockInfo") }
  );

  await ourModule.functionBeingTested("test");  // ...and wait for the Promise to resolve
  expect(mockInfo).toHaveBeenCalled();  // SUCCESS
});

【讨论】:

  • 当然——既然你指出了这一点,那就很明显了。我对异步代码很陌生,所以我没有想到。非常感谢。
  • @ScottMartin 没问题,很高兴它有帮助
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-08-26
  • 2021-12-01
  • 2019-07-03
  • 2023-03-14
  • 1970-01-01
  • 2021-05-01
  • 1970-01-01
相关资源
最近更新 更多