gpt4 book ai didi

node.js - Sinon - 什么时候使用 spy /模拟/ stub 或者只是简单的断言?

转载 作者:搜寻专家 更新时间:2023-10-31 22:57:42 25 4
gpt4 key购买 nike

我正在尝试了解如何 Sinon在 Node 项目中正确使用。我已经看过示例和文档,但我仍然不明白。我已经设置了一个具有以下结构的目录来尝试使用各种 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);
});
});

但我也看到过在这种情况下使用 stubs 的示例,例如

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 模拟数据库的引用资料,并尝试关注 this answer但我不知道什么是最好的方法。

最佳答案

你在一个帖子里问了很多不同的问题……我会试着整理一下。

  1. 用两个函数测试 myFuncs。

Sinon 是一个具有广泛功能的模拟库。 “模拟”意味着您应该用模拟或 stub 替换将要测试的部分内容。 Sinon documentation中有一篇不错的文章这很好地描述了差异。当您在这种情况下创建 spy 时...

var spyFunc1 = sinon.spy(myFuncs.func1);
var spyFunc2 = sinon.spy(myFuncs.func2);

...您刚刚创建了一个观察者。 myFuncs.func1 和 myFuncs.func2 将被替换为 spy 函数,但它将用于记录调用参数并在之后调用真正的函数。这是一种可能的情况,但请注意,myFuncs.func1/func2 的所有可能的复杂逻辑都将在测试中调用后运行(例如:数据库查询)。

2.1。 describe('Function 1', ...) 测试套件在我看来太做作了。

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

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

var test = sinon.stub().returns(200);
assert.equal(myFuncs.func1(test), 200);

即使将返回部分替换为 100,测试也会成功运行。一个有意义的是,例如,用 stub 替换 func2 以避免在测试中启动繁重的计算/远程请求(数据库查询、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);

因为在这种情况下,您使用 stub 屏蔽了真正的 func1 逻辑,而您实际上是在测试 sinon.stub().return()。相信我效果很好! :D

  1. 模拟数据库查询。模拟数据库一直是一个障碍。我可以提供一些建议。

3.1。有很好的碎片化环境。即使对于一个小项目,也最好存在一个开发、阶段和生产完全独立的环境。包括数据库。这意味着您有一种自动创建数据库的方式:脚本或 ORM。在这种情况下,您将使用 before()/beforeEach() 轻松维护测试引擎中的测试数据库,从而为您的测试提供一个干净的结构。

3.2。有很好的碎片化代码。最好有几层。最低层(DAL)应该与业务逻辑分离。在这种情况下,您将为业务类编写代码,只是模拟 DAL。要测试 DAL,您可以使用您提到的方法(sinon.mock 整个模块)或一些特定的库(例如:用 SQLite 替换数据库引擎以进行测试,如 here 所述)

  1. 结论。 “一旦我的程序变得更复杂,这些简单的测试方法将如何演变”

除非您在开发应用程序时考虑到测试,否则很难维护单元测试,因此非常分散。坚持主要规则——让每个单元测试尽可能小。否则你是对的,它最终会变得困惑。因为你的应用程序不断发展的逻辑会涉及到你的测试代码。

关于node.js - Sinon - 什么时候使用 spy /模拟/ stub 或者只是简单的断言?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28626597/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com