Unit testing flashcards
Fast, honest checks on small pieces of code, with Vitest, Jest and pytest examples from real projects.
Beginner friendly, starts from zero
0
Unit testing at a glance
A unit test is a small piece of code that checks another small piece of code gives the right answer.
Like a smoke alarm for code: quiet when all is fine, loud the moment something breaks.
Words you will meet
- Function
- A named piece of code that takes inputs and returns an output
- Test
- Code that runs a function and checks its answer
- Assertion
- The line that says what the answer must be
- Matcher
- The kind of check, such as toBe for 'is exactly'
- Test runner
- The tool that finds tests, runs them and prints a report
- Regression
- Something that used to work and now does not
- Refactor
- Tidy code without changing what it does
The steps
- 1. Start from zero (12 cards): What a unit test is, why it matters, and the words you need before Core basics.
- 2. Core basics (15 cards): Your first real test, assertions that explain failures, and the traps beginners hit.
- 3. Next steps (16 cards): Mocks at the right boundary, fixtures, async, timers, coverage and flaky tests.
- 4. Go deeper (17 cards): Design for testability, mutation and property testing, mock internals and scale.
All 12 cards in Start from zero
- What is a unit test, in one plain sentence?
- A unit test is a small piece of code that checks another small piece of code gives the right answer, every time you run it.
- Before tests, how did people know a change had not broken anything?
- They clicked through the app by hand after every change, which was slow and easy to skip. Bugs slipped out to users, and nobody dared tidy old code.
- Where do you already meet the idea of a test in daily life?
- When you change a recipe, you taste it before serving. When you fix a bike, you ride it round the block. Apps you use run thousands of such checks before each update.
- What is a good everyday picture of a unit test?
- A smoke alarm for your code. It stays quiet while everything is fine and goes off loudly the moment something breaks, pointing at the room with the problem.
- What do function, input, output and return mean?
- A function is a named little machine in code. You give it inputs, it does its job, and it returns an output:
add(2, 3)returns5. - What do test, assertion, matcher, pass and fail mean?
- A test runs a function and states what the answer must be; that statement is the assertion. In JavaScript it reads
expect(result).toBe(5), wheretoBeis the matcher. Right answer: pass. Wrong: fail. - What is a test runner, and what are Vitest, Jest and pytest?
- A test runner is a tool that finds your tests, runs them all and prints a report. Vitest and Jest are runners for JavaScript and TypeScript; pytest is the runner for Python.
- What do bug, regression and refactor mean?
- A bug is a mistake in code. A regression is something that used to work and now does not. To refactor is to tidy code without changing what it does.
- What are the terminal, a command and CI?
- The terminal is a window where you type commands, like
npx vitest, to run things. CI (continuous integration) is a robot server that runs all your tests on every change you share. - Your first tiny win: what does this code do?
- First comes the function, then the test with a plain name.
expect(add(2, 3)).toBe(5)says the answer must be 5; the runner shows pass or fail. - What do you need before you start?
- A little of one language, JavaScript or Python: variables and functions are enough. Then a text editor, a terminal, and Node.js or Python installed on your computer.
- After this topic, what will you be able to do?
- Write and run unit tests in Vitest or pytest, pick the right check for numbers, objects and errors, read a failure report, and keep tests fast and trustworthy.
Unit testing cheatsheet
Vitest and Jest assertions
expect(x).toBe(y)Same value or reference (Object.is)expect(x).toEqual(y)Deep equalityexpect(x).toStrictEqual(y)Deep, plusundefinedkeys and typesexpect(n).toBeCloseTo(0.3)Float comparisonexpect(() => fn()).toThrow(/msg/)Expect an error with messageawait expect(p).rejects.toThrow()Async error, must awaitexpect.objectContaining({ id })Partial matchtest.each(rows)("%s", fn)Table-driven test
Mocking
vi.fn().mockResolvedValue(v)Async mock functionvi.spyOn(obj, "method")Watch or override one methodvi.mock("./mod", () => ({...}))Replace a module, hoistedvi.hoisted(() => ({ m: vi.fn() }))Values usable invi.mockvi.stubGlobal("fetch", f)Replace a globalvi.useFakeTimers()Control timers andDatevi.advanceTimersByTime(300)Move fake timetoHaveBeenCalledWith(...)Check call arguments
pytest
@pytest.fixtureReusable setup,yieldfor teardown@pytest.mark.parametrize("a, b", rows)Table of caseswith pytest.raises(ValueError, match="x"):Expect an exceptionmonkeypatch.setenv("KEY", "v")Patch for one testtmp_pathTemporary folder fixturepytest.approx(0.3)Float comparisoncapsys.readouterr()Captured stdout and stderr
Command line
npx vitestWatch modenpx vitest run -t "coupon"Run once, filter by namenpx vitest run --coverageCoverage reportnpx vitest run --shard=1/4Split across CI machinespytest -x --lfStop on first fail, rerun last failurespytest -k "coupon and not slow"Filter by expressionpytest -n autoParallel withpytest-xdist
Config that prevents bugs
restoreMocks: trueRestore spies before each testunstubGlobals: trueUndovi.stubGlobalafter each testcoverage.thresholdsFail CI below a floorsequence: { shuffle: true }Expose order dependenceonUnhandledRequest: "error"MSW fails on unmocked calls