【问题标题】:Jest: how to mock console when it is used by a third-party-library?开玩笑:当第三方库使用控制台时如何模拟控制台?
【发布时间】:2017-06-13 13:22:00
【问题描述】:

我正在尝试模拟 console.warn/error 但我不能。我使用了一个第三方库,它在里面调用了 console.warn。我需要测试它是否被调用。在我的测试用例中,我试图存根 console.warn 但它没有帮助。之后我尝试手动模拟控制台,但也没有成功。

console.warn = jest.fn();
testSchema('/app/components/Users/UserItem/UserItemContainer.js');
expect(console.warn).toBeCalled();

没用

console.warn = jest.fn();
testSchema('/app/components/Users/UserItem/UserItemContainer.js');
console.warn('error');
expect(console.warn).toBeCalled();

确实有效。

但我仍然在终端中看到console.warn node_modules/babel-relay-plugin/lib/getBabelRelayPlugin.js:138

【问题讨论】:

    标签: javascript unit-testing tdd jestjs


    【解决方案1】:

    您必须使用global 来访问全局上下文中的对象

    global.console = {warn: jest.fn()}
    expect(console.warn).toBeCalled()
    

    或者使用jest.spyOn添加到19.0.0

    jest.spyOn(global.console, 'warn')
    

    【讨论】:

    • 是的,伙计们,它有效。但有一件事是,在声明 global.console 之后,您必须需要该库。我做错了。我需要我的库,然后声明为全局的。谢谢。
    • 有趣的是,Jest 网站上的任何地方都没有记录这一点。我正在搜索,但找不到任何解释。
    • with typescript: error TS2322: Type '{ warn: Mock; }' 不可分配给类型 'Console'。
    • 只是为了让每个人都知道。 global.console = {...}抑制错误,而jest.spyOn(...) 不会。您决定是否要在测试中抑制错误。
    • 我更喜欢jest.spyOn(...),因为它更容易清理,而且我使用的是 TypeScript,但也想抑制输出中的错误,正如@a11smiles 提到的那样。所以我使用了jest.spyOn(global.console, "warn").mockImplementation(() => {}),它可以防止间谍调用底层console.warn
    【解决方案2】:

    使用jest.spyOn()mockRestore()

    const consoleWarnMock = jest.spyOn(console, 'warn').mockImplementation();
    ...
    consoleWarnMock.mockRestore();
    

    接受的答案不会恢复原始的console.warn(),并且会“损害”同一文件中的其他测试(如果在其他测试或正在测试的代码中使用了console.warn())。

    仅供参考,如果您在测试文件中使用console.warn = jest.fn(),它不会影响其他测试文件(例如,console.warn 将在其他测试文件中恢复其原始值)。

    建议:您可以在 afterEach()/afterAll() 中调用 consoleWarnMock.mockRestore() 以确保即使测试崩溃,它也不会影响同一文件中的其他测试(例如,确保测试在同一文件中完全隔离)。

    完整示例:

    const consoleWarnMock = jest.spyOn(console, 'warn').mockImplementation();
    console.warn('message1'); // Won't be displayed (mocked)
    console.warn('message2'); // Won't be displayed (mocked)
    expect(console.warn).toHaveBeenCalledTimes(2);
    expect(consoleWarnMock).toHaveBeenCalledTimes(2); // Another syntax
    expect(console.warn).toHaveBeenLastCalledWith('message2');
    expect(consoleWarnMock).toHaveBeenLastCalledWith('message2'); // Another syntax
    expect(consoleWarnMock.mock.calls).toEqual([['message1'], ['message2']]);
    expect(console.warn.mock.calls).toEqual([['message1'], ['message2']]);
    consoleWarnMock.mockRestore(); // IMPORTANT
    //console.warn.mockRestore(); // Another syntax
    
    console.warn('message3'); // Will be displayed (not mocked anymore)
    expect(consoleWarnMock).toHaveBeenCalledTimes(0); // Not counting anymore
    expect(consoleWarnMock.mock.calls).toEqual([]);
    //expect(console.warn.mock.calls).toEqual([]); // Crash
    

    你不会写

    console.warn = jest.fn().mockImplementation();
    ... 
    console.warn.mockRestore();
    

    因为它不会恢复原来的console.warn()

    /!\ 使用mockImplementationOnce(),您仍然需要调用consoleWarnMock.mockRestore()

    // /!\
    const consoleWarnMock = jest.spyOn(console, 'warn').mockImplementationOnce(() => {});
    console.warn('message1'); // Won't be displayed (mocked)
    expect(console.warn).toHaveBeenCalledTimes(1);
    expect(consoleWarnMock).toHaveBeenCalledTimes(1); // Another syntax
    expect(console.warn).toHaveBeenLastCalledWith('message1');
    expect(consoleWarnMock).toHaveBeenLastCalledWith('message1'); // Another syntax
    expect(consoleWarnMock.mock.calls).toEqual([['message1']]);
    expect(console.warn.mock.calls).toEqual([['message1']]);
    
    console.warn('message2'); // Will be displayed (not mocked anymore)
    // /!\
    expect(console.warn).toHaveBeenCalledTimes(2); // BAD => still counting
    expect(consoleWarnMock.mock.calls).toEqual([['message1'], ['message2']]);
    expect(console.warn.mock.calls).toEqual([['message1'], ['message2']]);
    
    consoleWarnMock.mockRestore(); // IMPORTANT
    //console.warn.mockRestore(); // Another syntax
    console.warn('message3'); // Will be displayed (not mocked anymore)
    expect(consoleWarnMock).toHaveBeenCalledTimes(0); // Not counting anymore
    expect(consoleWarnMock.mock.calls).toEqual([]);
    //expect(console.warn.mock.calls).toEqual([]); // Crash
    

    你也可以写:

    const assert = console.assert;
    console.assert = jest.fn();
    ...
    console.assert = assert;
    

    【讨论】:

    • 这个解决方案对我不起作用;开玩笑 25.5.4。它只是不模拟控制台方法。调用次数为零,原始方法(对我来说是console.error)仍然被调用。
    • @cst1992 嘿,你有没有找到其他方法来测试它,如果有,请告诉我们那会很棒,我也被这个问题困扰。
    • @SakthiSureshAnand 还没有运气:(
    • @cst1992 哦不 :( 我也是,还没找到
    • 我打算建议监视globalThis.console 而不仅仅是console,这对我有用,但现在我发现普通的console 也对我有用(Jest 26.6)所以也许我只是幸运? :(祝你好运!
    【解决方案3】:

    您可以尝试以下方法,测试并确保在您的 jest 配置文件中包含 clearMockstrue

    test('it should console warn a message', ()=>{
        jest.spyOn(global.console, 'warn').mockImplementation();
    
        console.warn('my error');
        expect(console.warn).toBeCalledTimes(1)
        expect(console.warn).toBeCalledWith('my error');
    })
    
    module.exports = {
        ...
        clearMocks: true,
        ...
    }
    

    【讨论】:

      猜你喜欢
      • 2018-12-30
      • 1970-01-01
      • 1970-01-01
      • 2017-03-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多