Skip to content
Getting Digital

Unit Testing

Also: unit test, component testing, automated testing, test pyramid, test-driven development, TDD, test coverage

Unit testing is the practice of writing small automated checks that call one piece of code in isolation, a function, a class or a module, with known inputs and assert on its outputs, so that a change which breaks that behaviour fails a test within seconds of being made.

Assessment. Unit tests are the only tests fast enough to run on every change, which is why they form the base of the test pyramid. Their number is not a measure of quality: tests should cover the rules the business depends on, mocks should be confined to system boundaries, and coverage should be read as a map of untested code rather than as a target.

A unit test has three parts whatever the language: arrange the inputs and any collaborators, act by calling the code under test, assert that the result matches what the specification says. It runs without a database, a network or a browser, which is what makes it fast, and a suite of a few thousand tests runs in under a minute. Frameworks follow one family, xUnit, that began with Kent Beck's SUnit and now includes JUnit, pytest, Jest and their equivalents in every language; a Python developer and a JavaScript developer write the same shape of test in different syntax. ISTQB calls this level component testing, and the Foundation Level exam tests the vocabulary of levels, from component through integration and system to acceptance.

The test pyramid, drawn by Mike Cohn and written up by Martin Fowler in 2012, says where the effort should go: many unit tests at the base, fewer tests through a service layer in the middle, and few tests that drive the user interface at the top. The reasoning is cost and trust. Tests that run end to end through a browser are slow to run, expensive to write and break for causes unconnected to the code, which leads a team to disregard failing results. Unit tests fail for one reason, in one place, in a second, and so are acted on. A suite shaped like an inverted pyramid, with hundreds of browser tests and few unit tests, is the common shape of a project that automated its manual test plan instead of designing a test strategy.

What a unit test does not catch

The wrong requirement, a broken database query, a misconfigured server, two correct modules that disagree about a date format. Those need integration tests, contract tests and a staging environment. A green unit suite says the pieces work as their author understood them, nothing more.

Two habits decide whether a suite helps or hinders. The first is test doubles: a stub returns a canned answer so that the test does not touch the network, a mock additionally checks that it was called as expected. Used at the boundary they make tests fast; used everywhere they produce tests that pass while the real system fails, because every collaborator was replaced by an assumption. The second is test-driven development, Beck's 2002 discipline of writing the failing test first, making it pass with the simplest code and then tidying; it is less a testing technique than a design one, and it produces code that can be tested because it was written to be. Both habits are taught in the software testing courses and practised in the pipeline: a suite that runs on every push is the reason continuous integration can call a build self-testing.

In practice

  • The rule: an order over 100 euros ships free; at or below, shipping is 4.90. Two tests pin the boundary: 100.00 pays shipping, 100.01 does not.
  • The refactor: six months later someone rewrites the pricing module. The boundary test fails because the new code uses a greater-or-equal comparison. The failure arrives in the editor, before the pull request, with a message that names the rule.
  • The ineffective test: a test that mocks the pricing module and asserts the mock was called with the order. It passes before and after the bug and would have passed if shipping were free for everyone.

Often confused with

Continuous Integration (CI)
Unit tests are the checks; continuous integration is the practice of running them, with the build, on every merge to a shared mainline. A project can have thousands of tests that run only on a developer's machine, and a pipeline that runs none.

Key takeaways

  • →Arrange, act, assert: one unit, no network, no database, seconds to run. Speed is what makes the suite get used.
  • →Pyramid, not inverted pyramid: many unit tests, fewer service tests, few browser tests.
  • →Test the rules a customer depends on; mock only at the boundary; read coverage as a map of what is untested, not as a score.

Related concepts

Where this concept sits in the field

Certifications that test this

Vendor exams whose syllabus covers this concept: facts, cost and a preparation path on each page.

FAQ

What coverage percentage should a project aim for?
None in particular. Coverage shows which lines no test executes, which is useful for finding untested rules; as a target it produces tests written to touch lines rather than to check behaviour. Teams that care about the rules usually end up high anyway.
Should every function have a test?
Every rule should. A function that formats a date for display may not need one; the function that decides whether a payment is refundable does. Tests cost maintenance, and a test for trivial code is cost without benefit.
Is test-driven development worth learning?
Yes, as a design discipline, even for people who later write tests after the code. Writing the test first forces a decision about the interface before the implementation exists, and that decision is where most untestable code is born.

Sources

The primary text this definition rests on. Read it before relying on this one.

Last reviewed 3 October 2026 · Getting Digital