QA · Read 7 min

Unit tests: what they are and how to write your first one

The smallest unit of trust in your code. If you cannot test a function in isolation, you probably do not fully understand it either.

A unit test is a piece of code that runs another piece of code and checks that the result is the one you expected. Nothing more. You take a function, feed it a known input, and verify that it returns the correct output. If it matches, the test passes. If it does not, it fails and warns you before a user ever does.

That is the short answer. The useful answer is understanding why this test, the smallest of them all, is the foundation everything else rests on. It is called "unit" because it examines a unit: the smallest piece of your program that makes sense to test on its own, almost always a function or a method.

01 · the foundationWhat a unit test is and what makes it a "unit"

Think of the testing pyramid, a model that arranges test types by quantity and speed. At the base sit many unit tests: fast, cheap, isolated. In the middle, fewer integration tests, which check that several pieces fit together. And at the top, a handful of end to end tests, which walk through the whole system the way a person would. The pyramid shape is not decorative: it tells you how many tests of each type you should have. Martin Fowler popularized this figure based on the work of Mike Cohn [1].

What makes a unit test a "unit" is isolation. It tests a single thing, without depending on the database, without calling the network, without touching the system clock or reading a file. If your test needs all of that to run, it is no longer a unit test: it is an integration test, and it belongs to another level of the pyramid.

If you cannot test a function without booting up half the application, the problem is not the test: it is the design of the function.

That constraint has a valuable side effect. Writing the test forces you to reason about what the function receives, what it returns, and what it depends on. A function that is hard to test is usually a function that does too much, or that hides its dependencies. The unit test is, without meaning to, a detector of poor design.

Figura 1 · la pirámide de pruebas
E2E Integration Unit many · fast · cheap few · slow · expensive
The lower you go, the more tests you should have: they are fast and isolated. The higher you go, the fewer, because they are slow and brittle. The wide base holds up everything else.

02 · the patternArrange, act, assert: the anatomy of every test

Almost every well written unit test has three parts, always in the same order. In English it is known as AAA: arrange, act, assert. Prepare the scenario, run the action, state the truth.

Arrange. You set the stage: you create the input data and any object the function needs. Act. You call the function you want to test, once, with that data. Assert. You compare what it returned against what you expected. If it does not match, the test fails.

Let us look at the minimal example. Suppose a function that adds two numbers. The test reads almost like a sentence.

Figura 2 · una prueba unitaria en sus tres actos
1 · ARRANGE a = 2 b = 3 expected = 5 2 · ACT result = add(a, b) 3 · ASSERT assert result == expected
Three blocks, one single path. You prepare the input, call the function once, and assert the result. If the assertion is false, the test shouts.

That assert is the heart. An assertion that states, without ambiguity, what has to be true. When the function breaks in the future, because someone touched it by accident, that line is the one that will trip the alarm. A good unit test ideally has one clear assertion: it tests one thing and gives a concrete reason when it fails.

A test that never fails proves nothing

The beginner mistake is writing a test that always passes, even with the function broken. Before you trust a test, break it on purpose: change the function so it gives a wrong result and confirm that the test fails. If it stays green with the function broken, your test is looking the wrong way.

03 · the valueWhy they are fast, cheap and the first line of defense

A unit test runs in milliseconds because it touches nothing external. You can have thousands and run them all in seconds, every time you save a change. That very short cycle is what makes them cheap: the cost of writing one is low, and the cost of running it is almost zero. Kent Beck built test driven development on exactly that idea, writing the test before the code so the design is born already verified [2].

The value is not in one test, but in having them all running together. When you change a function and unwittingly break another one ten files away, the test for that other function fails immediately. You find out in seconds, not in production. That is a safety net, and it is what lets you modify code with confidence instead of with fear.

Without unit tests, every change is a bet. With them, it is a hypothesis verified on the spot.

The ISTQB, the international testing certification body, places the unit test as the first test level, the one closest to the code and the one run by those who write it [3]. It is no accident that it comes first: the sooner a defect is caught, the cheaper it is to fix. A bug caught by a unit test costs minutes; the same bug discovered by a customer costs reputation.

There is an honest limit worth stating. Unit tests check that each piece works on its own, but not that the whole system works together. You can have a hundred perfect functions that, assembled, do something wrong. That is what the other levels of the pyramid are for. The unit test is not all of quality: it is its foundation. And a solid foundation is the condition for everything above it to hold.

Start small. Take the simplest function you have, one that receives something and returns something, and write it a test with the three acts: prepare an input, call it, assert the output. Break it to confirm the test warns you. That first green test, which runs in the blink of an eye, is the smallest unit of trust you can build on top of your code. Everything else rests there.

Fuentes

  1. Fowler, M. (2012). Test Pyramid. martinfowler.com/bliki/TestPyramid.html. (Populariza la figura a partir de Cohn, M., Succeeding with Agile, Addison-Wesley, 2009.)
  2. Beck, K. (2002). Test-Driven Development: By Example. Addison-Wesley Professional. ISBN 978-0321146533.
  3. ISTQB (International Software Testing Qualifications Board). Certified Tester Foundation Level Syllabus, sección sobre niveles de prueba (component/unit testing). istqb.org.
  4. ISO/IEC/IEEE 29119-4. Software and systems engineering. Software testing. Part 4: Test techniques. International Organization for Standardization.

Learn more about AI

See all Learn AI