Unit test in JavaScript: checking one function, cut off from the rest

A unit test checks one unit of code isolated from its dependencies: the three-step structure, what it catches, and what makes it turn brittle.
3 min read
Believemy logo

A discount function behaves well for six months. Then a colleague adds a special case, and the calculation starts mishandling carts above one hundred euros.

A unit test is the line of code that would have reported the regression within the second.


Definition

A unit test checks the behavior of one unit of code, usually a function, cut off from its dependencies: no network, no database, no real clock. It supplies an input, makes the call, and compares the output against what was expected.

JAVASCRIPT
import { expect, it } from "vitest";
import { discount } from "./cart.js";

it("takes 10 euros off above 100", () => {
  const total = 150;                 // arrange

  const result = discount(total);    // act

  expect(result).toBe(140);          // assert
});

Those three steps, arrange, act, assert, are the structure of nearly every unit test. A test that does not let them be seen is almost always a test doing too much at once.


Its place among the other tests

KindWhat it coversWhat it costs
UnitOne function, isolatedA few milliseconds
IntegrationSeveral pieces put togetherHundreds of milliseconds
End to endThe full journey inside a browserSeveral seconds

The table holds three columns because there are only three questions: what, at what price, and therefore in what quantity. Unit tests are the most numerous because they are the cheapest.


What makes a function testable

  • A returned value rather than an Side effect: whatever a plain return reveals can be tested in one line.
  • Dependencies received as arguments rather than hard-imported, which is what allows a Mock to be passed in at test time.
  • No hidden data: a Pure function always hands back the same thing for the same inputs, which is exactly what a test knows how to assert.
Good to know

When a test becomes painful to write, the problem is rarely the test. It is the sign that the function does two things, or that it fetches what it needs on its own.


Frequently asked questions

Question

How many tests for one function?

One per behavior, not one per line. In practice that means the nominal case, the boundaries, and the expected failure. Three tests describing three different situations are worth more than ten repeating the same one with different numbers.


Question

Should internal functions be tested?

No, test what is exported. An internal function is an implementation detail, and testing it freezes that detail: the slightest reorganization then breaks tests although no behavior changed. If an internal function deserves its own tests, it probably deserves its own module.


Question

Write the test before the code?

That is the principle of test-driven development, and it has a merit independent of the dogma: writing the call before the implementation forces the signature to be decided from the caller's point of view. Many teams apply it to calculation functions and skip it elsewhere.

Related terms

Discover our javaScript glossary

Every word of JavaScript explained simply: keywords, built-in objects, methods, errors and concepts. Clear definitions and examples that actually run, to learn and to troubleshoot.

Share this article

Want to help us? Share this article on your networks or even better: on your site, in an article or in your newsletter.