What a Test Actually Is
The word "test" sounds official and heavy, like an exam your code has to sit. That heaviness scares people off. Let's strip it down to what a test really is - smaller and far less magical than the word suggests. By the end of this phase you'll be able to read a test and know exactly what it's doing.
A test is just a small program that checks your code
What it actually is. A test is a tiny program whose only job is to:
- Run your real code with some inputs you choose.
- Compare what your code gave back against what you expected it to give back.
- Shout if those two things don't match.
That's the whole idea. There's no special magic - a test is ordinary code that calls your ordinary code and checks the answer. The "shouting" step has a name:
📝 Terminology. An assertion is a line in a test that says "this had better be true." assert that the result equals 90. If it is true, the test quietly moves on. If it isn't, the assertion fails, and that
failure is what makes the whole test fail. A test is really just one or more assertions wrapped around a call
to your code.
Here's the shape of every test you'll ever write, drawn out:
This is sometimes called Arrange–Act–Assert, and once you see it you'll spot it in every test. It's just "set things up, do the thing, check the thing."
A real example: a function and a test for it
Let's make it concrete. Say you wrote a small function that applies a 10% discount for members:
// price.js - the real code we want to trust
What just happened: nothing yet - that's just the code we wrote. It might be right, it might be wrong. We believe a $100 order for a member should cost $90, but belief isn't proof. A test turns the belief into a check.
Now here's a test for it, written with a common test runner's style (test and expect - used by tools like
Jest and Vitest):
// price.test.js - a small program that checks price.js
;
What just happened: this test calls your actual priceFor function with the inputs 100 and true, then
asserts the answer is exactly 90. The expect(...).toBe(...) line is the assertion - the "this had better be
true" check. There's nothing else to it: it's a few lines of normal code that exercise your code and verify the
result.
Watch it pass, then watch it fail
The whole value is in what happens when you run it. When the code is correct, the test runner is calm:
$ npm test
✓ members get 10% off (2 ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
What just happened: the runner found your test, ran it, the assertion held (90 === 90), so it printed a tick
and moved on. Green means: the behavior you described is true right now. That's all "passing" means - your
expectation matched reality this time.
Now suppose someone "improves" the code and fat-fingers the discount - 0.9 becomes 0.8:
Run the tests again, change nothing else:
$ npm test
✗ members get 10% off (3 ms)
expect(received).toBe(expected)
Expected: 90
Received: 80
3 | const result = priceFor(100, true);
> 4 | expect(result).toBe(90);
| ^
Tests: 1 failed, 1 total
What just happened: the assertion expected 90 but the code now returns 80, so the assertion failed, so the
test failed. And look at how useful the failure is: it tells you what it expected (90), what it actually got
(80), and the exact line where they disagreed. That's the net from Phase 1, working. You didn't ship a wrong
price; you got a red, specific, immediate "no" the moment the mistake entered the code.
⚠️ A test that never fails is a test that never helped. The failing run above is the whole point - a test earns its keep by going red when the behavior is wrong. We'll come back to this in Phase 3, because a surprising number of tests are written in a way that can never fail, and those are worse than no test at all.
💡 Key point. Green isn't the goal - trustworthy green is. A passing test is only meaningful if you've seen (or can believe) it would go red when the thing it guards actually breaks.
Why this saves you later
Once you see that a test is just "call the code, check the answer," the fog lifts. You stop imagining testing as some separate discipline with its own dark arts, and start seeing it as writing down, in code, the things you already believe about your program. "A member's $100 order costs $90." You believed that anyway - a test just makes the belief permanent and self-checking, so the day someone breaks it, the code says so out loud instead of you finding out from a refund request.
Recap
- A test is a small program that runs your real code with known inputs and checks the result.
- The check is an assertion - "this had better be true"; a failed assertion fails the test.
- Every test follows Arrange–Act–Assert: set up inputs, call your code, check the result.
- Passing means your expectation matched reality this run; a good failure message tells you expected vs. actual and where - that specificity is the net doing its job.
- A test only helps if it can fail when the behavior is wrong - aim for trustworthy green, not green at any cost.
You can now read a test and write one in your head. The last question is the one that keeps people sane: with limited time, what should you actually bother testing - and what's a waste?
← Guide overview · Phase 3: What's Worth Testing (Straight Talk) →
Before the quiz: without looking back, say (or jot down) the core idea of this phase in your own words.
Check your understanding 3 questions
1. What is a test, mechanically?
2. What three steps does every test follow?
3. Why must you make sure a test can actually fail?