Scaling JavaScript Apps – Part II: Test Driven Development

A multi-part look at how modern JavaScript development techniques and best practices are driving the Rich Internet Applications of tomorrow. Project structure, writing specifications, build processes, automated testing, templating and applying “separation of concerns” to the world of JavaScript are all to be covered. The IDE used will be Eclipse.

Coverage of web application test-driven development and its practice in JavaScript had previously been scarce at best. That is, until efforts from Christian and others brought it out from the dark and into the spotlight. Since then, a wealth of tools and libraries have begun sprouting from every corner of the web.

This post assumes you are familiar with TDD and have been won over by its benefits. You should already have an understanding of the iterative process to follow, as well as the necessity of stubbing and mocking dependencies to deliver true (rather… truthy) unit tests. If you’re still in the dark, I recommend Christian’s series of excellent tutorials. To see how deep the rabbit hole really goes, be sure to pick up a copy of his book Test-Driven JavaScript Development.

Getting right down to business, the following is an example spec for a core unit which accepts an array of apps and loads each in turn – appending each app’s output to the DOM. Don’t fret if it’s not suddenly clear what the test is trying to achieve. Simply familiarize yourself with the vocabulary of the testing libraries.

it('should load app and append its wrapped view', function() {
    // create test namespace
    namespace('tux.test');

    // create a test app and spy on any calls made to it
    this.testView = $('<div>')[0];
    tux.test.TestApp = Backbone.View.extend({
        el: this.testView
    });
    this.TestApp = sinon.spy(tux.test, 'TestApp');

    // initialize the unit under test, passing a reference to the fake app
    this.app = new App({
        modules: [{
            app: 'test',
            obj: 'TestApp',
            title: 'Test App'
        }]
    });

    // add the result to the test environment DOM
    setFixtures(this.app.el);

    // check that the app was initialized
    expect(this.TestApp).toHaveBeenCalled();

    // check that test app was bundled inside the core app
    expect($(this.app.el)).toContain('div#test');
    expect(this.app.$('#test')).toContain(this.testView);

    // check that the test app was prepended with an h2 header
    var h2 = $(this.testView).prev();
    expect(h2).toBe('h2');
    expect(h2).toHaveText('Test App');
});

The Testing Stack

There are quite a few libraries and tools at play here.

  • Jasmine – the base testing framework that defines how your specs are written and how to verify that the tests have passed successfully or failed miserably.
  • Sinon – flexible spy, stub and mock library to intercept dependencies. It also provides fake servers and timers which allow you to avoid asynchronous testing scenarios and keep your test suite running times to a minimum.
  • jasmine-sinon – provides syntactic sugar (in the form of Jasmine “matchers”) for verifying specs that involve sinon objects. This is also useful when running tests, as the matchers ensures the error messages are contextually accurate about why a given test has failed.
  • jasmine-jquery – most useful for interaction with the DOM. Provides management of remote and local markup dependencies and a comprehensive set of Jasmine matchers to verify end-result elements, attributes and even event handlers. Read more here.

This collection should provide all you need to write your specs. The last two pieces of the puzzle are JsTestDriver and the adaptor for Jasmine enabling you to execute your Jasmine-based syntax against all browsers that have been “captured” by JsTestDriver. Let’s see how these all stack up.

That sure is a lot of moving parts, but you’ll be glad to know that the authors have produced some fine source code that’s not beyond debugging should anything go wrong. I’ve highlighted the application itself is to emphasise that at the end of the day, it should be the only code to reach the production environment.

Detailed instructions on how to load your application, supporting libraries and finally app specs into the test runner environment can be found at this Wiki. Just a few dry runs should make painfully obvious the need to automate test execution, bringing us to the next part of the series – scripting a JavaScript build process to seamlessly clean, verify and compile your source code.

About these ads

One thought on “Scaling JavaScript Apps – Part II: Test Driven Development

  1. Pingback: Scaling JavaScript Apps – Part III: Ant Build Process « mod.js

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s