From Breakpoint to Unit Test

2025-07-07, Mon

The other day I was required to write some JavaScript code in text editor instead of IDE. So I tried to complete the task without setting any breakpoint: instead, all the functions I wrote were tested continuously. At first I was not sure whether the work could be done in time, but out of my surprise, not only it was completed ahead of time, I also have much more confidence with the code I delivered, knowing that any change I made could be verified without much hassle.

Let's have some quick code to show how it played out: take Mocha1 as example, we have:

Step 1: Prepare the Environment2

mkdir -p ~/Workspace/SampleJS
cd $_

# during the init process, set type to module and test command to mocha 
npm init

# skip this step if mocha has been installed globally already
npm install --save-dev mocha

Step 2: declare the interface that is going to be delivered, without implementation:

// ref: src/app.js
export function greetings(name) {

}

Step 3: define the test cases

// ref: test/app.test.js
import assert from 'node:assert';
import { greetings } from '../src/app.js';

describe('App', function() {
    describe('greetings', function() {
        it('default', function() {
            assert.equal(greetings(), 'Hello, John Doe');
        });

        it('with name', function() {
            assert.equal(greetings('Jane'), 'Hello, Jane');
        });
    });
});

Step 4: Run the test case

npm test

All test cases should fail at this point, since no implementation has been provided yet.

With things set up properly, the development cycle boils down to

Initially I thought this process couldn't beat "debugging with breakpoint" in terms of development efficiency. I'm glad I was wrong: not only this process provides a better view of the overall project design, it also tracks the evolution of development naturally through accumulating test cases, which is very much welcome.

In the case of something goes wrong, it is usually reflected in failed tests, whose granularity could be controlled freely. With properly defined scope, the place where things might have gone wrong could be located fairly easily. In most cases, that's exactly what we wanted, and this approach is way more efficient than debugging line by line, not to mention that test cases could be version controlled as well.


It has long been my habit to set up some breakpoints and start debugging when things do not work as expected. For server side JavaScript, the typically way would be either use some IDE (i.e. VS Code, IntelliJ, etc.), or open chrome://inspect in Chrome after the Node inspector is enabled3:

node --inspect-brk src/app.js

This approach still works fine, but perhaps it's time to put it to the second chair.

As for unit test frameworks:

More testing frameworks for other languages could be found in the Wiki entry11.

Footnotes:

1

Mocha test framework https://mochajs.org

2

Code sample here uses ECMAScript Module by setting type to module in package.json, with export and import. Without this config, it's the default CommonJS module that that will be used by Node.js, with exports and require.

4

Jest testing framework https://jestjs.io

7

Unity: unit testing for C https://www.throwtheswitch.org/unity

8

Check: unit testing framework for C https://libcheck.github.io/check/