Testingbeginner
Unit Testing Fundamentals with Jest
The core building blocks of writing unit tests — test/describe blocks, assertions with expect, and the arrange-act-assert structure — using Jest as the representative framework.
A unit test states the setup, the action and the expectation.
Unit tests are like a series of small, automated inspections on an assembly line: instead of a human periodically eyeballing finished products for defects, a machine automatically checks a very specific measurement (one assertion) on every single unit that passes by, immediately flagging exactly which measurement failed and by how much, rather than a vague 'something seems off' after the fact.
Key Concepts
1
describe('calculateTotal', () => {
it('applies the bulk discount above 100 units', () => {
// arrange
const order = { quantity: 150, unitPrice: 10 };2
// act
const total = calculateTotal(order);3
// assert
expect(total).toBe(1350);
});
});4
Arrange, act, assert is the structure worth keeping. A test where the three are tangled is hard to read
when it fails.
5
The matchers you will use.
toBe(x) ===, for primitives
toEqual(x) deep equality, for objects
toStrictEqual(x) also checks undefined keys and class
toContain(x) array or string
toThrow() the function throws
toHaveBeenCalledWith a mock's arguments
resolves / rejects for promises6
toBe against toEqual is the common mistake.
expect({ a: 1 }).toBe({ a: 1 }); // fails -- different objects
expect({ a: 1 }).toEqual({ a: 1 }); // passestoBetoEqual
7
Name tests by behaviour, not by method.
it('returns the total') // says nothing
it('applies the bulk discount above 100') // says what it does8
When it fails, the name should tell you what broke without opening the file.
9
One assertion per behaviour. Several assertions about one behaviour are fine. A test asserting three
unrelated things fails on the first and hides the rest.
10
Setup and teardown.
beforeEach(() => { db = createTestDb(); });
afterEach(() => { db.close(); });11
beforeEach over beforeAll unless setup is expensive — shared state between tests is the most common
cause of tests that pass alone and fail together.
beforeEachbeforeAll
12
Test the behaviour, not the implementation.
expect(result.total).toBe(1350); // behaviour
expect(service.calculateSubtotal).toHaveBeenCalled(); // internals13
The second breaks when you refactor, which is exactly when you most want the test to keep working.
14
And the rule about coverage of the interesting cases. The boundary values — 99, 100, 101 — and the error
paths matter more than the happy path, which is usually the one that already works.
15
What the interviewer is probing.1. "What makes a good unit test?" Probing: the principles. Stalls: "It passes." Moves up:
it tests one behaviour through the public surface, is independent of other tests, and fails for
exactly one reason.
16
2. "What should you not test?" Probing: judgement. Stalls: "Nothing is off limits." *Moves
up:* implementation details and third-party code — asserting private calls makes refactoring break
tests that should not care.
17
3. "What is the arrange-act-assert shape for?" Probing: structure. Stalls: "Style." *Moves
up:* it keeps setup, action and verification separate so a reader sees what is being tested and what
is incidental.
18
4. "Why does test independence matter?" Probing: the failure mode. Stalls: "It is tidy."
Moves up: shared state makes failures depend on order, which produces intermittent failures nobody
can reproduce.