QuestionsTesting

What makes a good unit test

Unit Test QualityEasyTesting

What properties distinguish a good unit test from a bad one? What is the AAA structure?

What it tests

Recognizing the qualities — focused, deterministic, isolated, readable — that make tests worth having.

Approach & answer

A good unit test is FAST, ISOLATED, DETERMINISTIC, and tests ONE behavior with a clear name. Fast: it runs in milliseconds with no network, filesystem, or timers, so you can run thousands on every save. Isolated: it doesn't depend on other tests, execution order, or shared mutable state — each test sets up and tears down its own world, so a failure points at one thing. Deterministic: same input, same result, every run — no reliance on the current time, random values, network, or race conditions (those cause flakiness, the thing that destroys trust in a suite). Focused: it asserts one behavior, so its name can say exactly what broke ('returns 0 for an empty cart') and a failure is diagnostic rather than 'something in this 200-line test'. Readable: the test doubles as documentation of what the code should do. The AAA structure organizes each test into three visual phases: ARRANGE (set up inputs, state, and any doubles), ACT (invoke the one thing under test), ASSERT (check the outcome). Keeping those phases distinct — and having a single Act — keeps tests honest: multiple Acts usually means you're testing multiple behaviors and should split. Good tests also avoid logic (loops/conditionals in the test are a smell — they can hide bugs in the test itself) and test PUBLIC behavior, not private internals, so they don't break on every refactor. The payoff of these properties compounds: a fast, deterministic, well-named suite is one people actually run and trust; a slow, flaky, tangled one gets ignored or deleted.

Use this technique when

Reviewing test quality; structuring a new test; explaining why a test is brittle.

Code

// AAA: Arrange, Act, Assert — one behavior, clear name
test('applies a 10% discount to orders over $100', () => {
  // Arrange
  const cart = { subtotal: 150 };

  // Act
  const total = applyDiscount(cart);

  // Assert
  expect(total).toBe(135);
});

// Smell: two Acts / two behaviors in one test -> split it.
// Smell: relies on Date.now(), Math.random(), or a previous test's state.

References