Liqueed Project (3)

Previous Post
Next Post

I’m a big supporter of TDD (Test-Driven Development), and its workflow for software development. The software is created based on the tests that describe the expected behaviour, using the simplest possible implementation. For Liqueed Project, TDD was adopted during the creation of most of the code.

An example: there is a file, services\person.js, that is a JavaScript module. It manages the logic of the persons. A person can participate in zero, one or more projects, have sharepoints, vote, etc. And the system keeps the list of persons, retrieve a person by id, by username, … Part of the logic is in the service module. It was written using test/person.js for the tests of the logic. One test, one impementation, refactor, and so on. At the beginning of the test mode, there are some requires:

'use strict';

var service = require('../services/person');
var pservice = require('../services/project');
var async = require('simpleasync');

The services persons and project are used. simpleasync is a simple module I wrote to chaining callbacks. It was an interesting experience, and I’m doing “dog-fooding” in many projects.

Then, two module variables are declared, to be reused in the tests. They are the ids of some persons:

var annaid;
var lauraid;

To run the tests, I’m using simpleunit, another module I wrote, again, to practice JavaScript, TDD and simplicity. It is inspired by nodeunit, but it is simpler. simpleunit executes the module exported functions, providing a test object, something alike to assert in NodeJs.

The first tests exercises the creation of a person:

exports['add person'] = function (test) {
    test.async();

    service.addPerson({ name: 'Anna' }, function (err, result) {
        test.ok(!err);
        test.ok(result);
        annaid = result;
        test.done();
    });
};

It has a callback, so the function could end BEFORE the creation of the person. So, the test.async() tells to simpleunit to wait until the test.done() is reached. The above test only check the return of an id for the new person, and the value is saved in a module variable. This is something to discuss, but I found this way an easy one. The second tests depends on the first one. In C#, in other technologies, I wrote more isolated tests. But for me, in JavaScript, the level of isolation is the module, not the test function. In a module, a test function could depend on the execution of a previous one.

The second test:

exports['get person by id'] = function (test) {
    test.async();

    service.getPersonById(annaid, function (err, result) {
        test.ok(!err);
        test.ok(result);
        test.equal(result.name, 'Anna');
        test.equal(result.id, annaid);
        test.equal(result.username, 'anna');
        test.done();
    });
};

Using the id generated by the first test, the person is retrieved, and the data is checked.

This test series doesn’t use a predefined domain, and it does not assume a previous well-knoen status. And these tests are implemented using an in-memory domain. In the initial iterations, this in-memory domain was the only implementation. Only after the implementation of the first big use case, we added a domain persisted in MongoDB.

Stay tuned!

Angel “Java” Lopez

http://www.ajlopez.com

http://twitter.com/ajlopez