0

I'm building a midly size app using backbone and its friends jquery and underscore. My plan is to use QunitJS to create unittests.

I already have a Proof-Of-Concept of the app, so I basicly have a good grasp of how the code should look like without having to test it. It looks like that:

(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... 
})();

Otherwise said:

  • I wrap the module inside a function to avoid pollution
  • Class declaration and class use is interleaved
  • event registration is interleaved with the rest of the code
  • variables global to the module are reused inside the module

Now I need to test that. The problem is, I think, mainly about event registration and plumbing.

My plan is to wrap the code in functions and export every function and objects I want to test. The code will look like this:

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;
})();

This is the first time I need to write tests in javascript for this kind of application so I'm wondering whether my approach to make the code testable is correct or can be improved. For instance, It seems silly to me to wrap the registration of events in function without arguments and call them immediatly.

Is there a javascript way to do this?

2 Answers 2

1

So I found an excellent way to test private functions while keeping my production code clean. I am not sure if you are using any build system like Grunt or Gulp, but if you are open to it you could do something like this:

//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'));
});

And the file could look like:

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

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

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

Everything between the test comments gets stripped out after the tests are run so the production code is clean. Grunt has a version of this and I assume any automated build system can do the same. You can even set a watch task so that it runs the tests on every save. Otherwise you'll have to manually remove the exported test object before deployment.

In the case of Backbone just attach a test object to the module and reference that object in the tests. Or if you really want to separate it, set the object in the global scope. window.testObject = { //list of objects and methods to test... }; and strip that code out before deployment.

Sign up to request clarification or add additional context in comments.

1 Comment

thanks! I don't use gulp or the like, I found a solution to my problem I will post it later.
0

Basically what I do is avoid any calls in the library I want to test. So everything is wrapped in a function and exported.

Then I have two other files one is main.js where I do the plumbing and should be tested using integration tests with selenium and tests.js which does unit testing.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.