【问题标题】:Muting stdout and stderr during Mocha tests在 Mocha 测试期间静音 stdout 和 stderr
【发布时间】:2014-09-13 14:17:51
【问题描述】:

我首先要承认我可能正在做一些我不应该做的事情。不过既然我已经这么深了,那我也应该明白为什么会这样了。

我正在使用 Mocha 测试一些 Node.js 代码。此代码使用 Winston 日志库,该库直接调用 process.stdout.write()process.stderr.write() (source)。它运作良好;我对这种行为没有任何抱怨。

但是,当我对这段代码进行单元测试时,Mocha 测试运行器的输出偶尔会穿插日志输出行,这在某些记者(dotbdd)和其他人( xunit)。我想在不修改或继承 Winston 的情况下阻止此输出,并且如果可以避免的话,我想避免修改应用程序本身。

我得到的是一组实用函数,可以暂时用无操作函数替换 Node 内置函数,反之亦然:

var stdout_write = process.stdout._write,
    stderr_write = process.stderr._write;

function mute() {
    process.stderr._write = process.stdout._write = function(chunk, encoding, callback) {
        callback();
    };
}

function unmute() {
    process.stdout._write = stdout_write;
    process.stderr._write = stderr_write;
}

在各种测试规范中,我在任何产生不需要的输出的调用或断言之前直接调用了mute(),之后直接调用了unmute()。感觉有点 hacky,但它确实有效——运行测试时,控制台上没有出现一个字节的不需要的输出。

现在变得奇怪了!

我第一次尝试将输出重定向到文件:

mocha spec_file.js > output.txt

不需要的输出又回来了!发送到标准输出的每一条输出都出现在文件中。添加2>&1,我也得到了文件中的stderr。不过,无论哪种情况,控制台上都不会出现任何内容。

为什么两个调用之间的测试代码表现如此不同?我的直觉猜测是 Mocha 正在做某种测试以确定它是否正在写入 TTY,但我无法发现它改变写入行为的明显地方。

还有一个更广泛的问题,是否有任何正确方法可以在测试期间静音 stdout/stderr,而无需将所有可能记录日志的应用程序代码包装在检查测试环境的条件中?

【问题讨论】:

  • 不知道 Winston,但有可能它会检查 stdout 和 stderr 是否是 tty,如果是,则行为不同(例如:登录颜色等)?如果是这样,我想不要覆盖write_write,而是创建一个“空”流并完全替换stdoutstderr。如果没有让温斯顿这样做的“全局设置”,我也会感到惊讶:静音。 (例如:将日志级别降至最低)。

标签: node.js unit-testing stdout mocha.js stderr


【解决方案1】:

我发现了这种行为的可能原因。它确实与 stdout/stderr 是否是 TTY 有关。

当脚本在控制台中运行时,它们都是 TTY,process.stdoutprocess.stderr 似乎是 tty.WriteStream 的实例,而不是我最初假设的 stream.Writable。就我的交互而言,这两个类确实没有那么不同——它们都有公共的write() 方法,这些方法调用内部的_write() 方法,并且都共享相同的方法签名。

当通过管道传输到文件时,情况会有所不同。 process.stdoutprocess.stderr 是不同类的实例,但并不是很熟悉。尽我所能,它是fs. SyncWriteStream,但这是在黑暗中刺伤。无论如何,这个类没有_write() 方法,所以试图重写它是没有意义的。

解决方案是上移一层并使用write() 而不是_write() 进行静音。它做同样的事情,并且无论输出到哪里,它都始终如一地做。

【讨论】:

    【解决方案2】:

    https://www.npmjs.org/package/mute

    it('should shut the heck up', function (done) {
        var unmute = mute()
        app.options.defaults = true;
    
        app.run(function() {
            unmute();
    
            helpers.assertFiles([
                ['package.json', /"name": "temp-directory"/],
                ['README.md',    /# TEMP.Directory/]
            ]);
    
            done();
        });
    });
    

    【讨论】:

      猜你喜欢
      • 2020-10-18
      • 2012-03-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-30
      • 1970-01-01
      • 1970-01-01
      • 2018-10-31
      相关资源
      最近更新 更多