Node.js我应该如何对调用其他函数的函数进行单元测试

时间:2016-05-21 15:00:16

标签: javascript node.js unit-testing testing

我想对我构建的模块进行单元测试。 给人一种看起来很像的印象.. MyModule的:

function MyModule(...) {
    var self = this;
    MyModule.init.call(self, ...);
}

util.inherits(MyModule, MySuperModule);

MyModule.init = function(...) {
...
};

MyModule.prototype.logic = function(..., done) {
   calls fnA, fnB, fnC, fnD conditionally
   done(...)
};

MyModule.prototype.fnA = function(...) {
...
};

MyModule.prototype.fnB = function(...) {
...
};

MyModule.prototype.fnC = function(...) {
...
};

MyModule.prototype.fnD = function(...) {
...
};

MySuperModule:

function MySuperModule(...) {
    ...
    }

    MySuperModule.prototype,fn = function(..., done) {
        var self = this;
        ...
        self.logic(..., function done(...) {
            ...
            done(...)
        });
    }

现在MyModule.logic()永远不会被用户显式调用,只调用MySuperModule.fn()。 所有其他MyModule函数也是如此,这些函数根据通过委托链传递的给定参数有条件地调用。

我的问题如下:

  • 我是否需要单独测试所有MyModule函数,或者只是使用涵盖所有可能场景的不同参数测试MySuperModule.fn()
  • 我知道我需要单独测试函数(如果我之前提出的问题是错误的,因为我根本不会真正测试MyModule函数),我将如何使用MySuperModule.fn( ),因为它的done()回调是通过依赖于调用MyModule.logic()done()回调的参数来调用的,这又取决于提供给MySuperModule.fn()参数的参数。

3 个答案:

答案 0 :(得分:2)

在我看来,你当然应该测试各个功能,无论用户是否直接调用它们。

单元测试的目的是尝试确保测试的各个单元执行他们期望的操作。如果您(相对)确定您的各个功能/单元的行为符合预期,您可以更加确信它们可以很好地相互协作。

很难真正从你的代码片段中收集模块的性质,因此建议如何实现测试很困难。但是,您似乎要问的是如何验证是否调用了done / callback函数以及使用哪些参数。 为此,我建议使用存根。我通常使用sinon,但我确信其他类似工具也可用。

    var sinon = require( "sinon" );
    var should = require( "chai" ).should();
    var yourModule = require( "your-module" );

    var doneStub = sinon.stub();
    yourModule.yourFunction( ..., doneStub );
    doneStub.should.have.been.called;
    var args = doneStub.getCall( 0 ).args;
    args[ 0 ].should.be.eql( ... );
    // etc etc 

您还应该考虑使用测试运行器,我喜欢mocha

答案 1 :(得分:2)

这实际上取决于你如何在MySuperModule上注入MyModule。但首先我要指出,在单元测试中,你必须单独测试MyModule,MySuperModule使用MyModule的Mocked版本和所有其他依赖项。这是因为你不想两次测试MyModule,不需要那样。

因此,为了创建存根,有一个名为Sinon.JS的库可以正常工作。

因此,如果出于任何原因你只想对MyModule进行间谍活动,这意味着你只是将一个监听器附加到MyModule(它应用于MyModule方法),它会计算并告知是否有一个给定的方法被调用以及如何调用。

var MyModuleMethodASpy = sinon.spy(MyModulem 'MethodA');
MySuperModule.someMethod();
assert(MyModuleMethodASpy.called)

因此,此代码创建一个间谍,在MySuperModule上触发一些方法并检查是否曾调用MyModule.MethodA()

如果要控制哪些依赖关系返回特定方法,您也可以创建存根,例如:

var MyModuleStub = sinon.stub(MyModule, 'MethodA').returns([...somedata]);

答案 2 :(得分:1)

你应该进行渐进式测试。你应该测试每一个功能。 在这里你怎么做。

  1. 编写父函数的测试用例。模拟它调用的内部函数。您可以使用sinon库进行模拟。
  2. 对于第二个问题,您可以使用sinon mock的yield函数来模拟任何回调函数,并且您还可以指定您希望从该回调中输出哪个。通过这种方式,您可以使用不同的方案测试多个自定义输出的功能。