在Mocha测试期间将stdout和stderr静音

时间:2014-07-22 16:27:41

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

我会先承认我可能正在做一些我不应该做的事情。但由于我已经深入了解,我不妨理解为什么会发生这种情况。

我正在使用Mocha来测试一些Node.js代码。此代码使用Winston日志记录库,该库直接调用process.stdout.write()process.stderr.write()source)。效果很好;我没有抱怨这种行为。

然而,当我对这段代码进行单元测试时,Mocha测试运行器的输出偶尔会散布着日志输出行,这在一些记者(dotbdd)中是非常丑陋的其他人无效(xunit)。我想在不修改或子类化Winston的情况下阻止此输出,我想避免修改应用程序本身,如果我可以避免它。

我得到的是一组实用程序函数,可以使用no-op函数临时替换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

不需要的输出回来了!发送到stdout的每个输出都出现在文件中。添加2>&1,我在文件中也得到了stderr。但是,无论如何,控制台上都没有显示任何内容。

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

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

2 个答案:

答案 0 :(得分: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();
    });
});

答案 1 :(得分:2)

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

当脚本在控制台中运行时,这些都是TTY,而process.stdoutprocess.stderr似乎是tty.WriteStream的实例,而不像我原先假设的那样{{1} }}。就我的互动而言,这两个类别并没有那么不同 - 都有公共stream.Writable方法调用内部write()方法,并且两者都共享相同的方法签名。

当管道传输到文件时,事情会有所不同。 _write()process.stdout是一个不太熟悉的不同类的实例。我能想到的最好,它是process.stderr,但这是在黑暗中刺伤。无论如何,这个类没有fs. SyncWriteStream方法,所以试图覆盖它是毫无意义的。

解决方案是向上移动一级并使用_write()代替write()进行静音。它做同样的事情,无论输出在哪里,它都会始终如一。