在Express单元测试中覆盖异步功能

时间:2014-04-24 01:51:34

标签: javascript node.js unit-testing express nodeunit

我一直在努力为今天的应用程序编写一些快速单元测试。我有一个异步函数,在app.js中进行一些应用程序设置,它会读取大量文件,因此需要一段时间。运行应用程序不是问题,单元测试是因为测试运行时,设置尚未完成。

所以我认为我会删除异步函数,让它调用一个重新定义的异步函数,它不会完成单元测试setUp,直到运行回调为止。

问题在于,当重新定义的函数运行时,即使测试将应用程序传递到设置中,它传递的应用程序实例也没有完成所有设置。似乎sinon.callsArgWith在参数周围设置了一个闭包,这样当函数运行时,它就具有预设置状态的args。

我还使用proxyquire来确保在测试运行之间获得新的模块负载(使用noPreserveCache)。

重新定义的函数在options参数中传递,sinon查找它并运行它,我认为这是它应该如何完成的,我读了20次文档并且找不到让代码运行的任何其他方式(这是使用sinon的正确方法吗?)

快递应用程序(v4)具有以下结构:

.
├── app.js
├── bin
│   └── www
├── lib
│   ├── async_function.js
│   ├── error_handlers.js
│   ├── helpers.js
│   └── options.js
├── package.json
└── test
    └── test.js

WWW:

var
  app   = require( '../app' ),
  server;

app.set( 'port', process.env.PORT || 3000 );

server = app.listen( app.get( 'port' ), function () {
  console.log( "Express server listening on port " + server.address().port );
});

app.js:

var
  async_function = require( './lib/async_function' ),
  express        = require( 'express' ),
  path           = require( 'path' ),
  app            = express(),
  options        = require( './lib/options' ),
  setupErrorHandlers = require( './lib/error_handlers' );

// do some app setup stuff
app.set( 'views', path.join( __dirname, 'views' ) );
app.set( 'view engine', 'hogan' );
app.disable( "x-powered-by" );

async_function( app, options, function ( err ) {
  if ( err ) console.log( "Error: " + err );
  setupErrorHandlers( app );
});

module.exports = app;

async_function.js:

module.exports = function ( app, options, cb ) {
  setTimeout( function () {
    if ( app.result ) {
      app.result += options.arg1 + options.arg2;
    }
    else {
      app.result = options.arg1 + options.arg2;
    }
    console.log( "async_function.js: app.result: " + app.result );
    cb();
  }, 10000 );
};

options.js:

module.exports = {
  arg1: "qwertyuiop",
  arg2: "asdfghjkl"
};

test.js:

var
  nodeunit = require( 'nodeunit' ),
  express  = require( 'express' ),
  helpers  = require( '../lib/helpers' );

exports[ 'stubbing a non returning async function with a custom function' ] =         nodeunit.testCase({
  setUp: function ( callback ) {
    var async_path = '../lib/async_function';
    this.app = express();
    var options = {
      arg1: "zxcvbnm",
      arg2: "1234567890"
    };
    helpers.setupTestExpressApp( async_path, this.app, options, callback );
  },

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

  'test1': function ( t ) {
    t.expect( 2 );
    t.ok( ( this.app.result !== undefined ), 'async_function produced a result' );
    t.equal( this.app.result, 'zxcvbnm1234567890', 'custom async function was called' );
    t.done();
  },

  'test2': function ( t ) {
    t.expect( 2 );
    t.ok( ( this.app.result !== undefined ), 'async_function produced a result' );
    t.equal( this.app.result, 'zxcvbnm1234567890', 'custom async function was called' );
    t.done();
  }
});

helpers.js:

var
  proxyquire = require( 'proxyquire' ).noPreserveCache(),
  sinon      = require( 'sinon' );

var setupTestExpressApp = function ( async_path, app, options, callback ) {
  var
    options, app, cb,
    async_function, async_function_stub, redefined_async_function;

  // Get a fresh copy of the async_function
  async_function = proxyquire( async_path, { } );

  // Create a stub
  async_function_stub = sinon.stub();

  cb = function ( err ) {
    if ( err ) console.log( "Error: " + err );
    console.log( "Setup complete redefined" );
    callback();
  };

  // Create the re-defined function
  redefined_async_function = function ( app, options, cb ) {
    async_function( app, options, cb );
  };

  // Instruct the stub to use the custom function with the prepared args
  async_function_stub.callsArgWith( 1, app, options, cb );

  // Run the app setup, passing in the stub, the express app and sneaking in the
  // redefined function in the options arg
  app = proxyquire( '../app', {
    './lib/async_function': async_function_stub,
    app: app,
    './lib/options': redefined_async_function
  });
};

module.exports = {
  setupTestExpressApp : setupTestExpressApp
};

我错过了一些明显/模糊的东西吗?或者是一些我不知道的简单方法?

我想会有这样的事情,在快递应用程序上运行一些测试似乎需要付出很多努力。

我真的很感激这方面的一些帮助,我完全没有想法。

0 个答案:

没有答案
相关问题