Jest:在单元测试中禁用控制台的更好方法

时间:2017-06-09 22:50:54

标签: javascript unit-testing mocking jestjs

我想知道是否有更好的方法禁用控制台错误 特定的Jest测试(即恢复原始每次测试之前/之后的控制台

这是我目前的做法:

describe("Some description", () => {
  let consoleSpy;

  beforeEach(() => {
    if (typeof consoleSpy === "function") {
      consoleSpy.mockRestore();
    }
  });

  test("Some test that should not output errors to jest console", () => {
    expect.assertions(2);

    consoleSpy = jest.spyOn(console, "error").mockImplementation();

    // some function that uses console error
    expect(someFunction).toBe("X");
    expect(consoleSpy).toHaveBeenCalled();
  });

  test("Test that has console available", () => {
    // shows up during jest watch test, just as intended
    console.error("test");
  });
});

是否有更简洁的方法来完成同样的事情? 我想避免spyOn,但mockRestore似乎只能使用

谢谢!

10 个答案:

答案 0 :(得分:29)

由于每个测试文件都在自己的线程中运行,因此如果要在一个文件中为所有测试禁用它,则无需还原它。出于同样的原因,你也可以写

console.log = jest.fn()
expect(console.log).toHaveBeenCalled();

答案 1 :(得分:27)

对于特定的spec文件,Andreas的足够好。以下设置将禁止所有测试套件的console.log语句,

jest --silent

(或)

要自定义warn, info and debug,您可以使用以下设置

<强> __测试__ / setup.js

global.console = {
    log: jest.fn()
}

<强> jest.config.js

module.exports = {
    verbose: true,
    setupTestFrameworkScriptFile: "<rootDir>/__tests__/setup.js",
};

答案 2 :(得分:13)

我发现上面的答案是:在调用任何其他console.log方法(例如consolewarn)时,所有测试套件中的error都会导致错误正在替换整个全局console对象。

这种有点类似的方法适用于Jest 22 +:

的package.json

"jest": {
  "setupFiles": [...],
  "setupTestFrameworkScriptFile": "<rootDir>/jest/setup.js",
  ...
}

开玩笑/ setup.js

jest.spyOn(global.console, 'log').mockImplementation(() => jest.fn());

使用此方法,仅模拟console.log,其他console方法不受影响。

答案 3 :(得分:3)

对我来说,一种更清晰/干净的方法(读者几乎不需要jest API的知识就可以了解正在发生的事情),就是手动执行嘲讽还原操作:

// at start of test you want to suppress
const consoleLog = console.log;
console.log = jest.fn();

// at end of test
console.log = consoleLog;

答案 4 :(得分:3)

beforeAll(() => {
    jest.spyOn(console, 'log').mockImplementation(() => {});
    jest.spyOn(console, 'error').mockImplementation(() => {});
    jest.spyOn(console, 'warn').mockImplementation(() => {});
    jest.spyOn(console, 'info').mockImplementation(() => {});
    jest.spyOn(console, 'debug').mockImplementation(() => {});
});

答案 5 :(得分:1)

另一种方法是使用process.env.NODE_ENV这种方式可以在运行测试时有选择地选择显示(或不显示):

if (process.env.NODE_ENV === 'development') {
  console.log('Show output only while in "development" mode');
} else if (process.env.NODE_ENV === 'test') {
  console.log('Show output only while in "test" mode');
}

const logDev = msg => {
  if (process.env.NODE_ENV === 'development') {
    console.log(msg);
  }
}
logDev('Show output only while in "development" mode');

这将需要将此配置放置在package.json上:

"jest": {
  "globals": {
    "NODE_ENV": "test"
  }
}

请注意,这种方法不是原始问题的直接解决方案,但是只要可以将console.log用上述条件包装起来,就可以给出预期的结果。 < / p>

答案 6 :(得分:0)

如果您只想进行特定的测试:

beforeEach(() => {
  jest.spyOn(console, 'warn').mockImplementation(() => {});
});

答案 7 :(得分:0)

感谢@Raja 的最佳答案。这是我正在使用的(我会评论,但不能在评论中共享多行代码块)。

使用 jest v26,我收到此错误:

We detected setupFilesAfterEnv in your package.json.

Remove it from Jest configuration, and put the initialization code in src/setupTests.js:
This file will be loaded automatically.

因此,我不得不从我的 jest 配置中删除 setupFilesAfterEnv,并将其添加到 src/setupTests.js

// https://stackoverflow.com/questions/44467657/jest-better-way-to-disable-console-inside-unit-tests
const nativeConsoleError = global.console.error

global.console.error = (...args) => {
  if (args.join('').includes('Could not parse CSS stylesheet')) {
    return
  }
  return nativeConsoleError(...args)
}

答案 8 :(得分:0)

由于 jest.spyOn 对此不起作用(过去可能有过),因此我使用 jest.fn 进行手动模拟恢复,如 Jest docs 中所述。这样,您就不会错过任何在特定测试中未被凭经验忽略的日志。

const consoleError = console.error

beforeEach(() => {
  console.error = consoleError
})

test('with error', () => {
  console.error = jest.fn()
  console.error('error') // can't see me
})

test('with error and log', () => {
  console.error('error') // now you can
})

答案 9 :(得分:0)

奇怪的是上面的答案(除了 Raja 的好答案,但我想分享其他人失败的奇怪方式以及如何清除模拟以便没有其他人浪费我所做的时间)似乎成功地创建了模拟但不要禁止将日志记录到控制台。

两者

const consoleSpy = jest.spyOn(console, 'warn').mockImplementation(() => {});

global console = {
   warn: jest.fn().mockImplementation(() => {});
}

成功安装模拟(我可以使用 expect(console.warn).toBeCalledTimes(1) 并且它通过了)但它仍然输出警告,即使模拟实现似乎应该替换默认值(这是在 jsdom 环境中) ).

最终我找到了一个解决问题的方法,并将以下内容放入您的配置中加载了 SetupFiles 的文件中(请注意,我发现有时 global.$ 在将 jquery 放入全局上下文时对我不起作用,所以我只是设置在我的设置中,我所有的全局变量都是这样)。

const consoleWarn = jest.spyOn(console, 'warn').mockImplementation(() => {});
const consoleLog = jest.spyOn(console, 'log').mockImplementation(() => {});
const consoleDebug = jest.spyOn(console, 'debug').mockImplementation(() => {});
const consoleError = jest.spyOn(console, 'error').mockImplementation(() => {});


Object.defineProperty(global, 'console', {value: {
                                            warn: consoleWarn,
                                            log: consoleLog,
                                            debug: consoleDebug,
                                            error: consoleError}});

感觉很难看,然后我必须在每个测试文件中放置如下代码,因为在 SetupFiles 引用的文件中没有定义 beforeEach(也许你可以将两者都放在 SetupFilesAfterEnv 中,但我还没有尝试过)。

beforeEach(() => {
  console.warn.mockClear();
});