Well I wrote some unit test “suite” (using mocha) for myself – a code style that would allow me to fit any test I write into it without thinking over each test. A most simple example is to test a WorkerController class’ constructor:
const worker_module = require('../../api/controllers/WorkerController.js'); const assert = require('assert'); const WorkerController = worker_module.WorkerController; function newCall(Cls, arguments) { return new (Function.prototype.bind.apply(Cls, [Cls].concat(arguments))); } describe('WorkerControllerConstruct', function() { describe('#constructor', function () { const inputs = Array.from({length: 20}, (x,i) => i); const testargs = []; for (const i of inputs) { for (const j of inputs) { testargs.push({ args: [i, j], expected: [ (workerController) => assert.equal(workerController.maxOpen, i), (workerController) => assert.equal(workerController.time, j), ] }); } } for (const testarg of testargs) { it('Construct with args (' + testarg.args.toString() + ')', function () { let args = testarg.args; let expectations = testarg.expected; let worker = newCall(WorkerController, args); for (const expected of expectations) { expected(worker); } }); } }); });
It works quite decent, I can easily add to testargs for more “parameterized test”. However it is quite verbose, it is unclear when what line of code is executed and there are many layers of callbacks.
Just as another example, where the parameterizing isn’t “trivial” (but rather manually selected), in this test I test a “counter object” where the number is created as YYXXXX(X) with YY being the year of the log-number and X’s the actual entry-number in that year:
describe('JobCountNumber', function() { describe('#nextNumber', function() { let testargs = [ { args: new JobCountNumber(0, 1), expected:[ (counter) => assert.equal(counter.currentYear, 0), (counter) => assert.equal(counter.currentNumber, 2) ] }, { args: new JobCountNumber(0, 29999), expected:[ (counter) => assert.equal(counter.currentYear, 3), (counter) => assert.equal(counter.currentNumber, 0) ] }, { args: new JobCountNumber(3, 0), expected:[ (counter) => assert.equal(counter.currentYear, 3), (counter) => assert.equal(counter.currentNumber, 1) ] }, { args: new JobCountNumber(3, 9999), expected:[ (counter) => assert.equal(counter.currentYear, 4), (counter) => assert.equal(counter.currentNumber, 0) ] }, { args: new JobCountNumber(14, 9999), expected:[ (counter) => assert.equal(counter.currentYear, 15), (counter) => assert.equal(counter.currentNumber, 0) ] }, { args: new JobCountNumber(15, 9999), expected:[ (counter) => assert.equal(counter.currentYear, 15), (counter) => assert.equal(counter.currentNumber, 10000) ] }, { args: new JobCountNumber(15, 99999), expected:[ (counter) => assert.equal(counter.currentYear, 16), (counter) => assert.equal(counter.currentNumber, 0) ] }, ]; for (let testarg of testargs) { it('NextNumber with args ' + testarg.args.toString(), function () { let args = testarg.args; args.nextNumber(); let expectations = testarg.expected; for (let expected of expectations) { expected(args); } }); } }); });
Is this a good code style? Or should I rewrite parametrized tests in another way? Could mocha help me further?