在 Mocha 测试期间静音 stdout 和 stderr

11

首先声明一下,我可能正在做一些不应该做的事情。但既然已经深入到这个地步,我还是想要理解为什么会出现这种情况。

我正在使用Mocha测试一些Node.js代码。这段代码使用了Winston日志库,它直接调用process.stdout.write()process.stderr.write() (源码)。它的表现很好;我对它的行为没有任何抱怨。

然而,当我单元测试这个代码时,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()。这感觉有点笨拙,但它起作用了 - 运行测试时控制台上没有一个字节的不需要的输出。

现在变得有些奇怪!

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

mocha spec_file.js > output.txt

不需要的输出回来了!每一个被发送到标准输出的输出都出现在文件中。添加2>&1,我也将标准错误写入到了文件中。但是控制台上没有任何输出。为什么测试代码在这两种调用之间表现如此不同呢?我的直觉猜测是Mocha正在进行某种测试,以确定它是否正在写入TTY,但我没有找到明显的更改其写入行为的地方。

另外一个更广泛的问题是,在测试期间有没有任何正确的方法来静音标准输出/标准错误,而不必将所有潜在记录应用程序代码包装在检查测试环境的条件语句中?


不知道Winston,但它是否检查stdout和stderr是否为tty,如果是,则行为会有所不同(例如:以彩色记录日志等)?如果是这样,我想不要覆盖write_write,而是创建一个“null”流并完全替换stdoutstderr。我也会感到惊讶,如果没有一个“全局设置”来使Winston做到这一点:静音。(即:将日志级别降至最低)。 - Nitzan Shaked
2个回答

5
请查看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();
    });
});

3
我发现了这个行为的可能原因。它确实与stdout/stderr是否是TTY有关。
当脚本在控制台中运行时,这两者都是TTY,而process.stdout和process.stderr似乎是tty.WriteStream的实例,而不是我最初认为的stream.Writable。就我的交互而言,这两个类并没有太大的区别——两者都有公共的write()方法,调用内部的_write()方法,并且两者具有相同的方法签名。
当管道输出到文件时,情况有所不同。process.stdout和process.stderr是另一种不太熟悉的类的实例。我能找到的最好的解释是fs.SyncWriteStream,但这只是无中生有的猜测。无论如何,该类没有_write()方法,因此尝试覆盖它是毫无意义的。
解决方案是在更高的水平上使用write()来进行静音操作,而不是使用_write()。它完成了相同的操作,并且无论输出去向如何,都可以保持一致。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接