运行单元测试时禁用winston日志记录?

Posted

技术标签:

【中文标题】运行单元测试时禁用winston日志记录?【英文标题】:Disable winston logging when running unit tests? 【发布时间】: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
  
   

【问题讨论】:

***.com/questions/22709882/… 【参考方案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

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

    要写入此info.log 的日志 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 在测试时不会中断,所以我们导出一个空对象。这很好,因为它会被嘲笑。

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

【讨论】:

【参考方案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,你可以像这样禁用它:

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

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

    jest-set-up/index.js

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

【讨论】:

感谢@Meyer 的编辑,我尝试使用 4 个空格,但不确定我的文本没有被格式化为代码 你知道如何与ava实现相同的目标吗? 我正在使用 winston 日常传输,如何跳过要记录的测试用例 这太棒了!!,你也可以分享任何测试文件吗?

以上是关于运行单元测试时禁用winston日志记录?的主要内容,如果未能解决你的问题,请参考以下文章

运行单元测试时禁用 Django South?

在 UI 测试/单元测试期间将自定义字符串写入日志

暂时禁用单个 Python 单元测试

在 SwiftUI 单元测试中禁用模拟器

运行单元测试时如何抑制来自 node.js 应用程序的应用程序日志消息?

Angularjs单元测试-将文本添加到textarea时禁用ng的不起作用