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

Posted

技术标签:

【中文标题】运行单元测试时如何抑制来自 node.js 应用程序的应用程序日志消息?【英文标题】:How to suppress application logging messages from a node.js application when running unit tests? 【发布时间】:2014-05-07 17:46:46 【问题描述】:

在使用 mocha 和 supertest 对我的 node.js 应用程序(基本上是一个 REST 后端)进行单元测试时,我只需要屏幕上的特定于测试的消息,但标准输出中也充满了应用程序日志消息。

我开始单元测试:

mocha -R spec .

... 并得到这个输出(这是它不应该的):

[App] Listening on port 3000 ...
[App] Starting app, hooray!

  Project API
    GET /projects
[App] entering "projects" module ...
      √ should return an array of projects (317ms)

我用 [App] 标记了应用程序日志消息。我真正想要的是单元测试的输出:

  Project API
    GET /projects
      √ should return an array of projects (317ms)

如何抑制应用程序的console.log/warn/error 输出,其中穿插着Mocha 的报告器输出?

解决方案:

按照 dankohn 的方法,我最终得到了这样的结果,这解决了我的问题(使用 winston 进行日志记录):

(在节点的“主”服务器文件 server.js 中:)

if (process.env.NODE_ENV !== 'test') 
    logger = new (winston.Logger)(
        transports: [
            new (winston.transports.Console)(),
            new (winston.transports.File)( filename: 'foo.log' )
        ]
    );
 else 
    // while testing, log only to file, leaving stdout free for unit test status messages
    logger = new (winston.Logger)(
        transports: [
            new (winston.transports.File)( filename: 'foo.log' )
        ]
    );

...并设置环境变量,每个单元测试文件都以:

process.env.NODE_ENV = 'test';

【问题讨论】:

嗨,我遇到了一些问题,我使用了类似的方法来修复它,但我仍然在控制台中遇到猫鼬错误。你知道怎么处理吗? 【参考方案1】:

在您的 app.js 中:

if (process.env.NODE_ENV !== 'test') 
  app.use(express.logger());

在每个 mocha 文件的顶部:

process.env.NODE_ENV = 'test';

更新:

我们在导入代码中使用这个函数:

function logExceptOnTest(string) 
  if (process.env.NODE_ENV !== 'test') 
    console.log(string);
  

然后,将您的所有console.log('it worked') 替换为logExceptOnTest('it worked')。基本技巧是使用环境变量作为你想要的日志级别的全局标志。

【讨论】:

哎呀——你猜对了,我使用的是 Express。感谢您及时的回复。我不能按原样使用您的解决方案,因为 express.logger() AFAIU 仅记录请求/响应,但不能用于应用程序日志记录(调试消息等)。但是从您的想法中提取本质,要走的路似乎是:(1)摆脱console.log(我目前正在使用)(2)改用可配置的日志框架(3)基于NODE_ENV env配置日志工具环境。现在我必须弄脏(2)和(3)...... 查看我的更新。如果您想要更多的日志记录功能,请参阅github.com/flatiron/winston,但我们还不需要它。 我确实希望在单元测试时记录消息,因为在编写单元测试时(提前),我仍然想看看应用程序的底层发生了什么。因此,我将采用您建议的改编版本:使用 winston 配置日志记录设施并使用 env 变量(如您建议的那样)来区分“测试”和“非测试”模式。在“测试”模式下,将应用程序消息记录到指定文件(保持单元测试输出干净) - 在“非测试”模式(= 生产模式)下,将应用程序消息记录到标准输出,通过管道传输到例如永远。 感谢您的帮助!我最终使用了 rlogger,只是将日志级别包装在检查环境变量中的“测试”字符串的周围。即仅在测试期间记录错误,否则在正常操作期间全部记录。【参考方案2】:

这是一个非常简单的解决方案,它使用SinonJS 的test stubs 在运行测试之前抑制所有console.log/info/warn/error 语句。

// my-method.js

export function myMethod() 
    console.log(`I'm about to return true`)
    return true


// my-method.test.js

import describe, it, before from 'mocha'
import chai from 'chai'
import sinon from 'sinon'
import chalk from 'chalk'
import myMethod from './my-method.js'

const expect = chai.expect

describe(chalk.underline('My Test Group'), () => 

    before(() => 
        sinon.stub(console, 'log')  // disable console.log
        sinon.stub(console, 'info')  // disable console.info
        sinon.stub(console, 'warn')  // disable console.warn
        sinon.stub(console, 'error')  // disable console.error
    )

    describe('myMethod', () => 
        it('should return true', () => 
            expect(myMethod()).to.be.true  // without printing to the console
        )
    )
)

// output

My Test Group
  myMethod
    ✓ should return true

【讨论】:

这看起来像我想要的方法,但我无法让它发挥作用。我已经在使用 sinon,那些stub 调用应该是所有需要的,对吧? 有时我需要将 stub/restore 放入测试本身以使其正常工作 这是正确的方法..应该被接受为解决方案!【参考方案3】:

已经回答但我想我会补充说你可以做这个用户winston.add()

var logger = new (winston.Logger)(
    transports: [
        new (winston.transports.File)(filename: 'node.log')
    ]
);

if (process.env.NODE_ENV === 'test') 
    logger.add(winston.transports.Console, prettyPrint: true);

【讨论】:

【参考方案4】:

您可以使用mocha-suppress-logs 隐藏成功测试生成的日志,但仍保留失败测试生成的日志以方便调试。

安装:

npm install --save-dev mocha-suppress-logs

然后像这样使用它:

const suppressLogs = require('mocha-suppress-logs');
 
describe('Something', () => 
  suppressLogs();
 
  it('should do something', () => 
    // test code
  );
);

您也可以对整个测试套件全局执行此操作。

这是模块的链接:

https://www.npmjs.com/package/mocha-suppress-logs

【讨论】:

以上是关于运行单元测试时如何抑制来自 node.js 应用程序的应用程序日志消息?的主要内容,如果未能解决你的问题,请参考以下文章

使用带有事务的内存数据库进行单元测试时,如何抑制 InMemoryEventId.TransactionIgnoredWarning?

Node.js Sinon测试替身

UICollectionView,来自注册为单元格的框架目标的 nib 在运行时失败

运行 Mongoose 时执行 ajax 调用时如何处理 Node.js 发现

Python如何抑制单元测试的tkinter mainloop()

如何在单元测试中抑制Spark记录?