You fix a VAT calculation, everything seems to work… and three weeks later, someone discovers that discounts no longer apply. An automated test is a small program that runs your code and checks that it produces the expected result. Run on every change, it detects these regressions within seconds.
Tests also bring:
- confidence to refactor: you can reorganize the code without fear;
- living documentation: tests show how to use a function;
- better design: code that is hard to test is often too tightly coupled.
The test pyramid
| Level | What is tested | Speed | Quantity |
|---|---|---|---|
| Unit | A function or an isolated module | Milliseconds | Many |
| Integration | Several modules together (route + database) | Seconds | Medium |
| End-to-end (E2E) | The whole application through the browser | Slow | Few |
We start with the base: unit tests.
Assertions with node:assert
Node.js provides the node:assert module. An assertion checks a condition and throws an AssertionError if it is false.
const assert = require("node:assert");
function prixTTC(ht, taux = 0.2) {
if (ht < 0) throw new RangeError("Negative price");
return Math.round(ht * (1 + taux) * 100) / 100;
}
// Simple values: strict comparison (===)
assert.strictEqual(prixTTC(10), 12);
assert.strictEqual(prixTTC(10, 0.055), 10.55);
// Objects and arrays: content comparison
assert.deepStrictEqual([1, 2].map((x) => x * 2), [2, 4]);
// Errors: pass a FUNCTION that assert will call
assert.throws(() => prixTTC(-1), RangeError);
// Regular expressions
assert.match("Order #123", /#\d+/);
Watch out for two pitfalls:
assert.equal(non-strict) uses==:assert.equal(1, "1")passes. Prefer the strict variants, or importrequire("node:assert/strict").assert.strictEqual({a: 1}, {a: 1})fails: two distinct objects are not===. UsedeepStrictEqual.
Choosing your test cases
For each function, ask yourself these questions:
- Nominal case: does normal use give the right result?
- Edge cases: zero, empty string, empty array, a single element, maximum values, rounding.
- Invalid inputs: wrong type, negative value,
undefined.
A clear error message helps enormously when a test fails:
assert.strictEqual(prixTTC(0), 0, "A zero price must stay zero");
Key takeaways
A test = prepare data, call the code, check the result. Use strict assertions, test edge cases, and keep tests fast and independent.
Exercises
Solutions and tests stay on the server. In the student space, your code is run and checked, and the tutor gives hints before the solution.
First assertions
The function
moyenne(notes)is provided. Write the functiontesterMoyenne()that usesassertto check:moyenne([10, 20])is15;moyenne([7])is7;moyenne([])throws aRangeError.
Then call
testerMoyenne()at the end of the file.function moyenne(notes) { if (notes.length === 0) throw new RangeError("Liste vide"); return notes.reduce((a, b) => a + b, 0) / notes.length; } function testerMoyenne() { // Vos assertions ici } testerMoyenne();A checker that catches bugs
Write
verifierSlugify(slugify)that receives an implementation ofslugifyand throws anAssertionErrorif it is incorrect. A correct implementation must:- turn
"Bonjour le Monde"into"bonjour-le-monde"; - trim leading/trailing spaces:
" Café "gives"cafe"(accents removed); - return
""for an empty string.
The validator will pass good and bad implementations to your function.
function verifierSlugify(slugify) { // Vos assertions sur slugify(...) }- turn
Choose the right assertion
Which assertion checks that
getUser()returns the object{ id: 1, nom: "Ada" }?- assert.strictEqual(getUser(), { id: 1, nom: "Ada" })
- assert.deepStrictEqual(getUser(), { id: 1, nom: "Ada" })
- assert.ok(getUser() == { id: 1, nom: "Ada" })
End-of-lesson quiz
Which test level should be the most numerous?
- End-to-end tests
- Unit tests
- Manual tests
What does
assert.equal(1, "1")from the classic node:assert module do?- It fails
- It passes, because it uses ==
- It throws a TypeError
Which is an edge case for an average function?
- [10, 20]
- An empty array
- [12, 14, 16]
The rest of the course
- Node's Test Runner: Organizing Your Tests15 min
- Async Tests and Test Doubles (Mocks, Stubs, Spies)18 min
- TDD and Test Frameworks: Jest and Vitest18 min
- Integration Tests, Coverage, and Continuous Integration18 min