组织中型 javascript 客户端应用程序的代码以进行测试

Organizing code of a midly sized javascript client side app for testing

我正在使用 backbone 及其朋友 jquery 和下划线构建一个中等大小的应用程序。我的计划是使用 QunitJS 创建单元测试。

我已经有了该应用程序的概念验证,因此我基本上可以很好地掌握代码的外观,而无需对其进行测试。看起来像这样:

(function() {
  // prepare some model
  var Query = BackboneModel.extend({});
  query = new Query();

  // register some events
  $('body.something').click(function() {
    query.set('key', 'value');
    # ...
  });

  // create some backbone view
  var QueryView = Backbone.View.extend({...})

  // init backbone view
  query.view = new QueryView();

  // add some plumbing here ...

  // and so on... 
})();

否则说:

现在我需要测试一下。问题是,我认为,主要是关于事件注册和管道。

我的计划是将代码包装在函数中并导出我要测试的每个函数和对象。代码将如下所示:

var app = (function() {
  var app = {}

  // prepare some model
  var Query = BackboneModel.extend({});
  app.query = new Query();

  // register some events
  app.registerEvent = function() {
    $('body.something').click(function() {
      query.set('key', 'value');
      # ...
    });
  };
  app.registerEvent();  // XXX: call immediatly

  // create some backbone view
  app.QueryView = Backbone.View.extend({...})

  // init backbone view
  app.query.view = new QueryView();

  // add some plumbing here ...
  // wrapped in function with correct arguments and call it immediatly

  // and so on... 

  // ...
  return app;
})();

这是我第一次需要在 javascript 中为此类应用程序编写测试,所以我想知道我使代码可测试的方法是否正确或是否可以改进。例如,在我看来,将事件注册包装在没有参数的函数中并立即调用它们似乎很愚蠢。

有javascript方法吗?

所以我找到了一种极好的方法来测试私有函数,同时保持我的生产代码干净。我不确定您是否使用任何构建系统,如 G运行t 或 Gulp,但如果您愿意接受它,您可以这样做:

//has a dependency of 'test' causing it to run testing suite first
gulp.task('js', ['test'], function() {
return gulp.src(source)
    .pipe(plumber())
    //create sourcemaps so console errors point to original file
    .pipe(sourcemaps.init())
    //strip out any code between comments
    .pipe(stripCode({
        start_comment: 'start-test',
        end_comment: 'end-test'
    }))
    //combine all separatefiles into one
    .pipe(concatenate('mimic.min.js'))
    //minify and mangle
    .pipe(uglify())
    .pipe(sourcemaps.write('maps'))
    .pipe(gulp.dest('dist/js'));
});

文件可能如下所示:

var app = (function () {
    function somePrivateFunction () {}
    function someotherPrivateFunction () {}

    var app = {
        publicFunction: function(){}
        publicVar: publicVar
    }

    /* start-test */
    app.test = {
        testableFunction: somePrivateFunction
    }
    /* end-test */
}());

在测试 运行 之后,测试注释之间的所有内容都会被删除,因此生产代码是干净的。 G运行t 有一个这样的版本,我假设任何自动构建系统都可以做同样的事情。您甚至可以设置一个监视任务,以便 运行 对每次保存进行测试。否则,您必须在部署之前手动删除导出的测试对象。

在 Backbone 的情况下,只需将测试对象附加到模块并在测试中引用该对象。或者如果你真的想分离它,将对象设置在全局范围内。 window.testObject = { //list of objects and methods to test... }; 并在部署前删除该代码。

基本上我所做的是避免在我想测试的库中进行任何调用。所以一切都包装在一个函数中并导出。

然后我还有另外两个文件,一个是 main.js,我在其中进行管道连接,应该使用 selenium 的集成测试进行测试,另一个是 tests.js,它进行单元测试。