【问题标题】:Disable winston logging when running unit tests?运行单元测试时禁用winston日志记录?
【发布时间】:2016-11-16 17:26:37
【问题描述】:

在执行节点模块的单元测试时,是否可以选择性地禁用 Winston 日志记录?

理想情况下,我希望在应用程序运行时进行日志记录以提供信息和调试目的,但在运行测试时不显示单元测试结果混乱。

我对 winston 的使用在我的模块内部,如下所示:

// MyModule.js
var logger = require('winston');
module.exports = function() {
  // does some stuff
  // and logs some stuff like so:
  logger.log('an informational message');
}

// MyModuleTest.js
describe('MyModule', fucntion() {
  it('should do some stuff', function() {
     var myModuleUnderTest = require('MyModule');
     // some tests
  }
}   

【问题讨论】:

标签: node.js unit-testing winston


【解决方案1】:

我做的有点难看,但让我可以继续正常使用 Jest 的 --silent 选项。我只是将 Winston 的 silent 设置为 process.argv.indexOf("--silent") >= 0。例如:

const logger = new winston.Logger({
  …,
  transports: [
    new winston.transports.Console({
      …,
      silent: process.argv.indexOf("--silent") >= 0,
    }),
  ],
});

【讨论】:

  • silent: process.env.NODE_ENV === 'testing' 也是一个选项
  • 是的。但是你不能直接使用 Jest 的 --silent 选项启用或禁用它,我觉得这很烦人。
  • 啊,我应该说只有当你总是想在运行测试时让winston静音时才可以选择。
  • 这在您测试一组测试文件时不起作用。看起来它不会使 argv 可供检查。
【解决方案2】:

我们在测试中使用了silent 属性:

import logger from './my-defined-winston-logger'


//...
beforeAll(() => {
  logger.silent = true;
})
afterAll(() => {
  logger.silent = false;
})

【讨论】:

    【解决方案3】:

    我意识到这已经很晚了,但我只是想用 jest 分享我的解决方案,因为我对这里找到的解决方案并不完全满意。我不能说我的解决方案非常优雅,并且可能只是隐藏了一些代码气味,因为我还在学习 TDD,但它确实有效。

    在我的工作中,我经常想登录到通过winston.transports.File(filename: "<filename>") 传输指定的文件。假设我的日志文件是info.log

    当然,在测试期间,我不想要

    1. 要写入此info.log 的日志
    2. info.log 不存在时创建。

    这样做是为了避免副作用。上面的答案以及嘲笑足以避免 1. 但由于某种原因并没有避免 2. (解释原因如下)。

    我设置项目的方式通常是这样的

       src
        ├── app.js
        ├── services
        │   ├── logging
        │   │   ├── logger.js
        │   │   └── logger_utils.js
        │   ├── foo.js
        │   ├── bar.js
        │   └── etc.js
        ├── tests
        │   ├── foo.test.js
        │   ├── bar.test.js
        │   └── etc.test.js
        └── logs
            └── info.log
    

    主要关注与日志相关的文件。 logger.js 是我实例化并随后导出winston Logger 对象的地方。然后我在logger_utils.js 中编写辅助函数,以实现模块化和更轻松的测试。

    当我的问题出现时,logger.js 包含在

    problematic_logger.js
    const winston = require("winston");
    const path = require("path");
    // define the log file directory
    const log_dir = path.resolve(__dirname, "./../../logs/info.log");
    // create logger
    const logger = winston.createLogger({
        transports: [
          new winston.transports.File({
            filename: log_dir
          })
        ]
      });
    // export it
    module.exports = logger;
    

    然后我在logger_utils.js 中需要它,而这又在任何其他模块脚本中需要。所以,在测试中(除了测试logger_utils.js),我只需要模拟logger_utils.js中包含的函数,不用担心logger.js,因为它只被logger_utils.js调用。

    现在,我对此并不完全确定,但我认为上面定义的 2. 尽管有模拟和静音,但仍然失败,因为 winston.createLogger() 仍在被调用,我相信即使在 - -silent 标志已设置。我不知道这是不是真的,但是上面的解决方案不起作用。

    所以,(受this answer 启发)我决定做的只是在测试时不创建任何winston 对象。我通过将logger.js 文件更改为

    fixed_logger.js
    const winston = require("winston");
    const path = require("path");
    // define the log file directory
    const log_dir = path.resolve(__dirname, "../../logs/info.log");
    // if we are testing, don't create any winston object
    if (process.env.NODE_ENV === "test") {
      // export
      module.exports = {};
    } else {
      // behave normally otherwise
      // create winston logger
      const logger = winston.createLogger({
        transports: [
          new winston.transports.File({
            filename: log_dir
          })
        ]
      });
      // export it
      module.exports = logger;
    }
    

    NODE_ENV 在运行npm testnpm run test:watch 等时自动设置为“测试”)

    我们仍然需要导出一些东西让 logger_utils.js 在测试时不会中断,所以我们导出一个空对象。这很好,因为它会被嘲笑。

    无论如何,这是我对 stackoverflow 的第一个回答。我希望这不会太灾难性,如果有人想了解更多细节,请告诉我。

    【讨论】:

      【解决方案4】:

      这是我的设置:

      const { createLogger, format, transports, config } = require("winston");
      
      let level, silent;
      switch (process.env.NODE_ENV) {
        case "production":
          level = "warning";
          silent = false;
          break;
        case "test":
          level = "emerg";
          silent = true;
          break;
        default:
          level = "debug";
          silent = false;
          break;
      }
      
      const options = {
        console: {
          level,
          silent,
          handleExceptions: true,
          format: format.combine(
            format.colorize(),
            format.splat(),
            format.printf(
              info => `${new Date().toISOString()} ${info.level}: ${info.message}`,
            ),
          ),
        },
      };
      
      const logger = createLogger({
        levels: config.syslog.levels,
        transports: [new transports.Console(options.console)],
        exitOnError: false,
      });
      
      module.exports = logger;
      

      【讨论】:

      • silent 是我正在寻找的参数。
      【解决方案5】:

      设置的东西对我不起作用,我使用的是winston v3.1.0,有一种创建记录器的新方法。

      来自温斯顿网站:https://github.com/winstonjs/winston

      推荐使用 winston 的方法是创建您自己的记录器。最简单的方法是使用 winston.createLogger:

      const logger = winston.createLogger({
          level: 'info',
          format: winston.format.json(),
          transports: [
            //
            // - Write to all logs with level `info` and below to `combined.log` 
            // - Write all logs error (and below) to `error.log`.
            //
            new winston.transports.File({ filename: 'error.log', level: 'error' }),
            new winston.transports.File({ filename: 'combined.log' })
          ]
        });
      
        //
        // If we're not in production then log to the `console` with the format:
        // `${info.level}: ${info.message} JSON.stringify({ ...rest }) `
        // 
        if (process.env.NODE_ENV !== 'production') {
          logger.add(new winston.transports.Console({
          format: winston.format.simple()
        }));
      }
      

      所以我在 logger.js 中这样做

      if (process.env.NODE_ENV === 'test') {
          return winston.createLogger({
            transports: [ new winston.transports.Console({ level: 'error'}) ]
          });
      }
      

      这会停止所有日志消息,除非您有错误,我希望看到这有助于调试任何问题。

      希望这会有所帮助。

      【讨论】:

        【解决方案6】:

        创建一个记录器:

        const logger = createLogger({
            level: "info",
            format: format.json(),
            transports: []
        });
        

        静默所有日志记录:

        logger.transports.forEach((t) => (t.silent = true));
        

        【讨论】:

          【解决方案7】:

          Winston 传输有一个 silent 可以设置的属性,这可能比删除整个传输要好一些。

          我为传输添加了一个名称,这样会更容易一些:

          var logger = new winston.Logger();
          
          logger.add(winston.transports.Console, {
              name: 'console.info',
              colorize: true,
              showLevel: true,
              formatter: consoleFormatter,
          })
          

          然后在测试或设置中,我可以有选择地打开和关闭登录:

          logger.transports['console.info'].silent = true  // turns off
          logger.transports['console.info'].silent = false // logging back on
          

          【讨论】:

          • 您可以将silent 添加到createLogger,而不是添加到每个传输器:createLogger({ silent: true, ... })。如果您想静默所有日志,这很有用。
          【解决方案8】:

          如果你使用的是 Jest,你可以像这样禁用它:

          1. 设置要在 jest 运行测试之前运行的设置文件。在package.json:

            {
                "jest": {
                    "setupFiles": ["<rootDir>/jest-set-up/index.js"]
                }
            }
            
          2. jest-set-up/index.js

            import winston from 'winston'
            winston.remove(winston.transports.Console)
            

          【讨论】:

          • 感谢@Meyer 的编辑,我尝试使用 4 个空格,但不确定我的文本没有被格式化为代码
          • 你知道如何与ava实现相同的目标吗?
          • 我正在使用 winston 日常传输,如何跳过要记录的测试用例
          • 这太棒了!!,你也可以分享任何测试文件吗?
          猜你喜欢
          • 2011-07-12
          • 2011-05-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-06-20
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多