如何测试开玩笑的 console.log

Posted

技术标签:

【中文标题】如何测试开玩笑的 console.log【英文标题】:How do I test a jest console.log 【发布时间】:2018-08-12 06:14:42 【问题描述】:

我正在使用 create-react-app 并尝试编写一个 jest 测试来检查 console.log 的输出。

我要测试的功能是:

export const log = logMsg => console.log(logMsg);

我的测试是:

it('console.log the text "hello"', () => 
  console.log = jest.fn('hello');
  expect(logMsg).toBe('hello');
);

这是我的错误

 FAIL  src/utils/general.test.js
  ● console.log the text hello

    expect(received).toBe(expected)    Expected value to be (using ===):      "hello"
    Received:
      undefined
    Difference:
      Comparing two different types of values. Expected string but received undefined.

【问题讨论】:

测试中函数的调用在哪里?您应该在进行断言之前调用它。 对不起,我不明白你的意思? 能否请您包含整个测试文件?你在哪里声明logMsg 这就是我所拥有的,logMsg 是传入的文本。 【参考方案1】:

如果您想检查console.log 是否收到了正确的参数(您传入的参数),您应该检查jest.fn()mock。 您还必须调用 log 函数,否则永远不会调用 console.log

it('console.log the text "hello"', () => 
  console.log = jest.fn();
  log('hello');
  // The first argument of the first call to the function was 'hello'
  expect(console.log.mock.calls[0][0]).toBe('hello');
);

it('console.log the text "hello"', () => 
  console.log = jest.fn();
  log('hello');
  // The first argument of the first call to the function was 'hello'
  expect(console.log).toHaveBeenCalledWith('hello');
);

阅读更多here。

【讨论】:

FAIL src/utils/general.test.js ● console.log 文本“hello” TypeError: specificMockImpl.apply is not a function at CustomConsole.mockConstructor [as log] (node_modules/jest-mock /build/index.js:288:37) 在 Object..exports.logger.logMsg (src/utils/general.js:13:51) 在 Object..it (src/utils/general .test.js:16:23) 在新 Promise () 在 Promise.resolve.then.el (node_modules/p-map/index.js:46:16) 在 我的错误。 jest.fn('hello') 应该是 jest.fn()。现在试试。此外,如果它回答了您的问题,您可以接受它作为正确答案。【参考方案2】:

或者你可以这样做:

it('calls console.log with "hello"', () => 
  const consoleSpy = jest.spyOn(console, 'log');

  console.log('hello');

  expect(consoleSpy).toHaveBeenCalledWith('hello');
);

【讨论】:

这是最安全、副作用最小的答案,我推荐它胜过其他解决方案。您也可以使用间谍来静音默认行为,并且 jest 将确保在测试结束时正确恢复所有内容(与大多数其他答案不同)。这也是最简洁和组合的方法。【参考方案3】:

另一种选择是保存对原始日志的引用,为每个测试替换一个开玩笑的模拟,并在所有测试完成后恢复。这对不污染测试输出并仍然能够使用原始日志方法进行调试有一点好处。

describe("Some logging behavior", () => 
  const log = console.log; // save original console.log function
  beforeEach(() => 
    console.log = jest.fn(); // create a new mock function for each test
  );
  afterAll(() => 
    console.log = log; // restore original console.log after all tests
  );
  test("no log", () => 
    // TODO: test something that should not log
    expect(console.log).not.toHaveBeenCalled();
  );
  test("some log", () => 
    // TODO: test something that should log
    expect(console.log).toHaveBeenCalled();
    const message = console.log.mock.calls[0][0]; // get log message
    expect(message).toEqual(expect.stringContaining('something')); // assert on the message content
    log(message); // actually log out what the mock was called with
  );
);

【讨论】:

唯一适用于独立测试的解决方案。这应该是公认的答案,因为其他解决方案会对已记录的内容给出错误的否定响应【参考方案4】:

我会考虑 toHaveBeenCalledWith 或 jest 提供的任何其他用于检查模拟调用的方法 (the ones that start with toHaveBeenCalled)。

it('console.log the text "hello"', () => 
  console.log = jest.fn();
  log('hello');
  expect(console.log).toHaveBeenCalledWith('hello');
);

【讨论】:

这是否与特定测试隔离? 您可以致电mockReset() od mockClear() 重置 concole.log 模拟。 嗯。我只是担心这样的声明会产生全球性的副作用。我只想在我知道要登录的测试中模拟控制台。然后结合测试并行运行的事实?如果它正在产生全局副作用,似乎重置日志是不够的,因为测试是并行运行的

以上是关于如何测试开玩笑的 console.log的主要内容,如果未能解决你的问题,请参考以下文章

开玩笑:如何测试对象键和值?

开玩笑;如何在字符串上测试 JSON.parse 会成功

如何允许 scss 开玩笑地对 typescript nextjs 进行单元测试?

使用 cdkFocusInitial 运行材质对话框组件的开玩笑单元测试时,如何修复“[cdkFocusInitial]”不可聚焦警告?

如何解决冲突:使用开玩笑快照测试时“在源上删除,在目标上修改”?

如何开玩笑地模拟 i18next 模块