Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Node.js Sinon-何时使用间谍/模拟/存根,还是仅使用简单的断言?_Node.js_Unit Testing_Tdd_Mocha.js_Sinon - Fatal编程技术网

Node.js Sinon-何时使用间谍/模拟/存根,还是仅使用简单的断言?

Node.js Sinon-何时使用间谍/模拟/存根,还是仅使用简单的断言?,node.js,unit-testing,tdd,mocha.js,sinon,Node.js,Unit Testing,Tdd,Mocha.js,Sinon,我试图理解如何在节点项目中正确使用。我已经看过了一些例子和文档,但是我还是不明白。我已经设置了一个具有以下结构的目录,以尝试和使用各种Sinon功能,并了解它们的适用范围 |--lib |--index.js |--test |--test.js index.js var myFuncs = {}; myFuncs.func1 = function () { myFuncs.func2(); return 200; }; myFuncs.func2 = functi

我试图理解如何在节点项目中正确使用。我已经看过了一些例子和文档,但是我还是不明白。我已经设置了一个具有以下结构的目录,以尝试和使用各种Sinon功能,并了解它们的适用范围

|--lib
   |--index.js
|--test
   |--test.js
index.js

var myFuncs = {};

myFuncs.func1 = function () {
   myFuncs.func2();
   return 200;
};

myFuncs.func2 = function(data) {
};

module.exports = myFuncs;
test.js
以以下内容开头

var assert = require('assert');
var sinon = require('sinon');
var myFuncs = require('../lib/index.js');

var spyFunc1 = sinon.spy(myFuncs.func1);
var spyFunc2 = sinon.spy(myFuncs.func2);
诚然,这是非常人为的,但就目前情况而言,我想测试对
func1
的任何调用是否会导致调用
func2
,因此我会使用

describe('Function 2', function(){
   it('should be called by Function 1', function(){
      myFuncs.func1();
      assert(spyFunc2.calledOnce);
   });
});
我还想测试
func1
是否会返回
200
,这样我就可以使用

describe('Function 1', function(){
   it('should return 200', function(){
      assert.equal(myFuncs.func1(), 200);
   });
});
但我也看到过在这种情况下使用
存根的例子,例如

describe('Function 1', function(){
   it('should return 200', function(){
      var test = sinon.stub().returns(200);
      assert.equal(myFuncs.func1(test), 200);
   });
});
这些有什么不同?
stub
提供了什么,而简单的断言测试没有

当我的程序变得更复杂时,这些简单的测试方法将如何发展,这是我头脑中最困难的问题。假设我开始使用
mysql
,并添加一个新函数

myFuncs.func3 = function(data, callback) {
   connection.query('SELECT name FROM users WHERE name IN (?)', [data], function(err, rows) {
          if (err) throw err;
          names = _.pluck(rows, 'name');
          return callback(null, names);
       });
    };

我知道当涉及到数据库时,有人建议为此目的使用一个测试数据库,但我的最终目标可能是一个包含许多表的数据库,而为了测试而复制它可能会很麻烦。我看到过关于用sinon模拟db的参考资料,并尝试了以下方法,但我不知道什么是最好的方法

你在一篇帖子上问了这么多不同的问题。。。我会设法解决的

  • 使用两个函数测试myFuncs Sinon是一个具有广泛功能的模拟库。“模拟”意味着您应该用模拟或存根替换将要测试的部分内容。有一篇好文章很好地描述了两者之间的区别。 当你在这种情况下创造了一个间谍

    var spyFunc1 = sinon.spy(myFuncs.func1);
    var spyFunc2 = sinon.spy(myFuncs.func2);
    
    …你刚刚创建了一个观察者。myFuncs.func1和myFuncs.func2将替换为间谍函数,但它将用于记录调用参数并在此之后调用实函数。这是一个可能的场景,但请注意,myFuncs.func1/func2的所有可能复杂的逻辑都将在测试中调用后运行(例如:数据库查询)

    2.1。对我来说,descripe('Function 1',…)测试套件看起来太做作了

    你到底指的是哪个问题并不明显。 返回常量值的函数不是实际示例。。在大多数情况下,会有一些参数,被测函数会实现一些转换输入参数的算法。因此,在测试中,您将部分实现相同的算法,以检查函数是否正常工作。这就是实现的地方,它实际上假设您从测试开始实现,并使用部分单元测试代码来实现被测试的方法

    2.2。树桩。在给定的示例中,单元测试的第二个版本看起来毫无用处。func1不接受任何参数

    var test = sinon.stub().returns(200);
    assert.equal(myFuncs.func1(test), 200);
    
    即使将返回部件替换为100,测试也将成功运行。 有意义的是,例如,用存根替换func2,以避免在测试中启动繁重的计算/远程请求(DB query、http或其他API请求)

    myFuncs.func2 = sinon.spy();
    assert.equal(myFuncs.func1(test), 200);
    assert(myFuncs.func2.calledOnce);
    
    单元测试的基本规则是单元测试应该尽可能简单,提供尽可能小的代码片段检查。在这个测试中,func1正在被测试,所以我们可以忽略func2的逻辑。应该在另一个单元测试中进行测试。 请注意,进行以下尝试是无用的:

    myFuncs.func1 = sinon.stub().returns(200);
    assert.equal(myFuncs.func1(test), 200);
    
    因为在本例中,您使用存根屏蔽了真正的func1逻辑,实际上您正在测试sinon.stub().return()。相信我,它工作得很好D

  • 模拟数据库查询。 模拟数据库一直是一个障碍。我可以提供一些建议
  • 3.1。具有良好的碎片化环境。即使是一个小项目,也最好有一个完全独立的开发、阶段和生产环境。包括数据库。这意味着您有一种自动创建数据库的方法:脚本或ORM。 在这个场景中,您将很容易地使用before()/beforeach()在测试引擎中维护测试数据库,从而为测试提供一个干净的结构

    3.2。拥有完整的代码片段。最好有好几层。最低层(DAL)应与业务逻辑分离。在本例中,您将为业务类编写代码,只需模拟DAL即可。要测试DAL,您可以使用您提到的方法(sinon.mock整个模块)或一些特定的库(例如:将db引擎替换为SQLite以进行所述的测试)

  • 结语。“一旦我的程序变得更复杂,这些简单的测试方法将如何发展”
  • 除非您在开发应用程序时考虑到测试,并且因此非常分散,否则很难维护单元测试。坚持主要原则-使每个单元测试尽可能小。否则你是对的,事情最终会变得一团糟。因为应用程序不断演化的逻辑将包含在测试代码中