簡體   English   中英

Node.js模塊單元測試-使用sinon.js暫存異步文件系統調用

[英]Node.js module unit testing - stubbing asynchronous file system calls with sinon.js

我已經為此苦苦掙扎了好幾個小時,而且我什么都沒走。 這是我正在使用的代碼的簡化版本:

我有一個名為“ setup”的模塊,該模塊在內部從文件系統讀取文件,並執行一些操作。 我試圖編寫一些使用存根返回假數據而不是從文件系統讀取的單元測試。 我正在使用nodeunit的沙盒功能,因為我正在存根的功能不會導出。

setup
├── data.js
├── index.js
├── loader.js
├── package.json
└── test
    └── test-setup.js

index.js:

var
  loader = require( './loader' );

module.exports = function () {
  // do stuff
  loader( function ( data ) {
    console.log( "read from file: " + JSON.stringify( data, null, 2 ));
    // do more stuff
    return data;
  });
};

loader.js:

module.exports = function ( cb ) {
  var data = require( './data' );
  cb( data );
};

data.js:

module.exports = {
  data: {
    field1: "value1",
    field2: "value2"
  }
};

test-setup.js:

var
  nodeunit = require( 'nodeunit' ),
  sandbox  = require( 'nodeunit' ).utils.sandbox,
  sinon    = require( 'sinon' ),
  loader   = require( '../loader' ),
  setup    = require( '..' );

exports[ 'setup file loading' ] = nodeunit.testCase ({
  setUp: function ( callback ) {
    var
      boxModule = { exports: {} },
      boxGlobals = {
        module  : boxModule,
        exports : boxModule.exports,
        loader  : loader,
        require : function () { return loader; },
        console : console
      };
    this.fakedata = {
      fakedata: {
        field1: "value1",
        field2: "value2"
      }
    };
    this.sandbox = sandbox( '../index.js', boxGlobals );
    callback();
  },

  tearDown: function ( callback ) {
    delete this.sandbox;
    callback();
  },

  'test1: setup by loading the file normally': function ( t ) {
    t.ok( setup() === undefined, 'data is undefined - has not loaded yet' );
    t.done();
  },

  'test2: setup using sandbox and loader function replaced with stub': function ( t ) {
    var fakedata = this.fakedata;
    var returnFakeData = function () {
      return fakedata;
    };
    var stub = sinon.stub( this.sandbox, 'loader', returnFakeData);
    t.equal( this.sandbox.module.exports(), this.fakedata, 'returned value is the fakedata from the stub' );
    t.done();
  }

});

測試1通過。 測試2失敗並顯示:AssertionError:返回的值是存根中的fakedata

日志消息顯示它已打印文件中的數據,而不是假數據。 當我在調試器中檢查this.sandbox.loader函數時,它已正確設置為存根。

第二個問題是,我不得不偽造require並通過以下方式傳入loader函數:

require:function(){返回加載器; },

否則要求找不到./loader。 我嘗試在測試之前使用process.chdir更改目錄,但是即使cwd正確設置為項目目錄,require仍然失敗。 顯然,偽造require僅在需要1個模塊的情況下有效,在實際代碼中有多個require。 我加載./loader的唯一另一種方法是修改代碼以使用絕對路徑,並且每次運行測試都編輯代碼是不可行的。

我可能已經錯過了一些顯而易見的事情,為異步加載數據的模塊代碼編寫單元測試必須是非常標准的事情。 沙箱/存根是正確的方法嗎?

任何幫助,不勝感激。

經過相當多的理智之后 ,我想出了一個使用proxyquire的解決方案,該解決方案“代理nodejs以便在測試期間覆蓋依賴項”。 比使用nodeunit沙箱要好得多。

我還必須更新模塊以接受回調函數,並修改loader.js以將函數導出為“ load”。

希望這對外面的人有用。

index.js:

var
  loader = require( './loader' );

module.exports = function ( file, cb ) {
  // do stuff
  loader.load( file, function ( data ) {
    console.log( "read from file: " + JSON.stringify( data, null, 2 ));
    // do more stuff
    cb ( data );
  });
};

loader.js:

module.exports = {
  load: function ( file, cb ) {
    var data = require( file );
    cb( data );
  }
};

test-setup.js:

var
  proxyquire = require( 'proxyquire' ),
  sinon      = require( 'sinon' ),
  pathStub   = {},
  fakedata   = {
    fakedata: {
      field1: "fakevalue1",
      field2: "fakevalue2"
    }
  },
  setup = proxyquire('..', {
    './loader': pathStub
  });

exports.testSetup = function ( t ) {
  pathStub.load = sinon.stub();
  pathStub.load.yields( fakedata );

  t.expect( 1 );
  setup( './data', function ( data ) {
    t.equal( data, fakedata, 'setup returned fakedata' );
    t.done();
  });
};

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM