繁体   English   中英

在Node.js中使用Sinon.js模拟Postgres进行单元测试

[英]Mocking Postgres for unit tests with Sinon.js in Node.js

我很难弄清楚如何使用sinon模拟对我正在测试的模块所要求的postgres的调用,或者甚至有可能。

我不是在尝试测试postgres模块本身,而只是为了确保它按预期运行,并且没有在测试该实例中应该调用的对象。

我猜这是节点的必需设置,因为我的模块需要postgres模块才能访问数据库,但是在这里,我不想运行集成测试,我只是想确保我的代码可以独立工作,而不是真的在乎数据库在做什么,我将把它留给我的集成测试。

我见过有人将其函数设置为具有可选参数,以将模拟/存根/伪造函数发送给该函数,测试其存在性以及是否在所需的模块上使用它,但这对我来说似乎是一种气味(我是Node的新手,所以也许不是)。

我更愿意对此进行模拟,而不是尝试并劫持需求(如果可能的话)。

一些代码 (请注意,这不是真正的代码,因为我正在使用TDD运行,并且该函数实际上没有执行任何操作,函数名称是真实的)

测试设置

describe('#execute', function () {
it('should return data rows when executing a select', function(){
 //Not sure what to do here
});
});

样例功能

PostgresqlProvider.prototype.execute = function (query, cb) {
var self = this;

if (self.connection === "")
    cb(new Error('Connection can not be empty, set Connection using Init function'));

if (query === null)
    cb(new Error('Invalid Query Object - Query Object is Null'))

if (!query.buildCommand)
    cb(new Error("Invalid Query Object"));

//Valid connection and query
};

像这样包装postgres模块可能看起来有点可笑,但是有一些设计,因为此应用程序将有几个“提供者”,我想为它们公开相同的API,以便可以互换使用。

更新

我认为测试太复杂了,因为我想看看是否进行了连接调用,然后返回了对我来说很香的数据,因此我将其剥离并放入两个测试中:

模拟测试

it('should call pg.connect when a valid Query object is parsed', function(){
        var mockPg = sinon.mock(pg);
        mockPg.expects('connect').once;            

        Provider.init('ConnectionString');
        Provider.execute(stubQueryWithBuildFunc, null, mockPg);

        mockPg.verify();
    });

这有效(我认为)是因为没有postgres连接器代码,它失败了,并且通过了(Boom :))

现在的问题是第二种方法,我将使用一个存根(也许是间谍),它应该在失败时通过100%,所以我会在早上捡起来。

更新2

我对测试不是100%满意的,主要是因为我没有劫持击中数据库的client.query方法,而只是劫持了我的execute方法并将其强制沿着一条路径,但是它使我可以看到结果并断言它可以测试行为,但是可以接受任何建议的改进。

我正在使用间谍程序来捕获该方法并返回null和一个包含行的伪对象,就像该方法将回传一样,随着我添加更多查询行为,该测试将发生变化,但它使我步履维艰。

    it('should return data rows when a valid Query object is parsed', function(){

        var fauxRows = [
            {'id': 1000, 'name':'Some Company A'},
            {'id': 1001, 'name':'Some Company B'}
        ];

       var stubPg = sinon.stub(Provider, 'execute').callsArgWith(1, null, fauxRows);

       Provider.init('ConnectionString');
       Provider.execute(stubQueryWithBuildFunc, function(err, rows){
           rows.should.have.length(2);
       }, stubPg);

       stubPg.called.should.equal.true;
       stubPg.restore();
    });

使用pg-pool: https : //www.npmjs.com/package/pg-pool

无论如何,它将被添加到pg中,据称可以使(模拟)单元测试更加容易...来自BrianC( https://github.com/brianc/node-postgres/issues/1056#issuecomment-227325045 ):

检出https://github.com/brianc/node-pg-pool-很快将在node-postgres中实现池实现,并且不依赖单例,这使得模拟变得更加容易。 希望有帮助!

我非常明确地替换了我的依赖项。 这可能不是最好的解决方案,但我看到的所有其他解决方案也都不太好。

inject: function (_mock) {
  if (_mock) { real = _mock; }
}

您将此代码添加到被测模块。 在测试中,我调用了inject方法并替换了真实对象。 我不100%喜欢它的原因是因为您只需要添加额外的代码即可进行测试。

另一种解决方案是将模块文件读取为字符串,然后使用vm手动加载该文件。 当我调查此问题时,发现它有些复杂,因此我只使用了inject函数。 不过,可能值得研究这种方法。 您可以在此处找到更多信息。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM