簡體   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