【问题标题】:Node.js how should I unit test a function calling other functionsNode.js我应该如何对调用其他函数的函数进行单元测试
【发布时间】:2016-09-18 18:29:48
【问题描述】:

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

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(...) {
...
};

我的超级模块:

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() 参数的参数。

【问题讨论】:

    标签: javascript node.js unit-testing testing


    【解决方案1】:

    这真的取决于您如何在 MySuperModule 上注入 MyModule。但首先我要指出的是,在单元测试中,您必须单独测试 MyModule,并使用来自 MyModule 的 Mocked 版本和所有其他依赖项测试 MySuperModule。这是因为您不想测试 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】:

      在我看来,您当然应该测试各个函数,无论它们是否由用户直接调用。

      单元测试的目的是确保您的测试的各个单元都能完成预期的工作。如果您(相对)确定您的各个功能/单元的行为符合预期,那么您可以更有信心地相信它们会很好地相互配合。

      很难从您的代码 sn-ps 中真正收集到模块的性质,因此很难提出如何实施测试的建议。但是,您似乎要问的是如何验证您的完成/回调函数是否被调用以及使用哪些参数。 为此,我建议使用存根。我通常使用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

      【讨论】:

        【解决方案3】:

        您应该进行渐进式测试。您应该测试每个功能。 在这里你可以如何继续。

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-07-16
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-05-16
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多