H Heygents Docs Open the app

Updated July 25, 2026 · About 9 min read

How to Keep a Test Suite Fast Enough to Run on Every Change

The short version: A test suite needs to finish fast enough that you never think twice before running it, and in practice that means seconds for the unit-test layer and about a minute for the whole suite. Get there with a broad base of unit tests, parallel execution across every core, running only the tests a change can affect, and isolating slow integration and end-to-end tests.

A test suite is only useful when you actually run it. The biggest reason a solo developer stops running tests isn't laziness - it's that the suite got slow. Speed isn't a vanity metric. It's the property that decides whether continuous testing survives past the first busy week.

Why speed is what makes continuous testing viable

The promise of continuous testing is simple: every change you make runs the tests, so a regression is caught the moment it's introduced rather than days later. That promise depends entirely on one number - how long the suite takes. A fast suite runs a hundred times a day without you thinking about it. A slow suite runs when you remember it, which is to say, rarely.

The math is unforgiving. If the suite takes ten seconds, you run it after every small edit and never lose the thread. If it takes five minutes, you start batching changes and running it "later," and "later" is where the regressions hide. The suite didn't become less correct, but it became less used, and a test that goes unused is worth nothing.

That's why speed comes before coverage. A ninety-percent-coverage suite you avoid running protects you less than a sixty-percent one that runs on every keystroke. The goal isn't the most tests - it's the most feedback per unit of your attention:

  • Fast enough to be invisible - a suite you never wait for is a suite you never skip.
  • Feedback while the change is fresh - a red test seconds after the edit tells you exactly what broke.
  • No temptation to batch - slow suites push you to batch changes, and that's where regressions accumulate.

The test pyramid for a solo developer

The classic shape of a healthy suite is a pyramid: a broad base of fast unit tests, a narrower band of integration tests, and a thin cap of end-to-end tests. The shape isn't aesthetic - it's a direct consequence of how long each type of test takes to run.

  1. Unit tests exercise a single function or module in isolation, with no network, no database, no browser. They run in milliseconds, so you can have thousands of them and still finish in seconds. This is where most of your coverage should be.
  2. Integration tests check that a few pieces work together - a handler talking to a real database, a service calling another service. They run in tens or hundreds of milliseconds each, so keep fewer of them and aim them at the seams that genuinely matter.
  3. End-to-end tests drive the whole application the way a user would, through a real browser or a full HTTP stack. Each takes seconds, so keep only a handful covering critical journeys that would be catastrophic to break.

The failure mode to avoid is the inverted pyramid - a suite too heavy with slow e2e tests because they felt more "real" to write. That gives you confidence right up until it gets so slow you stop running it. For a solo developer with no QA team, the pyramid isn't an example; it's the only shape that keeps the suite both trustworthy and fast enough to run all the time.

Tests that run themselves on every change

Heygents runs your test suite automatically on every change and reports back in seconds, not minutes. Instead of remembering to run tests, you get sub-minute feedback the moment you save - a red result surfaces while the edit is still fresh in your mind, and an AI agent can read the failure and propose the fix. Continuous testing stops being a discipline you keep and becomes something that just happens.

Open Heygents →

Run in parallel to use the whole machine

Most test runners run one test at a time by default, using a single core while the rest of your processor sits idle. On a modern laptop with eight cores, that means you're running the suite at roughly one-eighth of its potential speed. Parallel execution is the cheapest speedup available, because you already own the hardware.

The idea is to split the suite into groups that run at the same time across worker processes. A suite that takes forty seconds serially can drop under ten when spread across your cores, with no changes to the tests themselves beyond making sure they don't step on each other.

  • Turn on the runner's workers. Most modern runners parallelize with a single flag - use it, and set the worker count to match your cores.
  • Keep tests independent. Parallel execution only works if tests don't share mutable state. Give each worker its own fixtures, temp directories, and a separate database schema.
  • Avoid shared global setup. A single database everyone writes to serializes your workers. Isolate per worker so the parallelism is real.
  • Watch for order-dependence. Tests that only pass in a certain order have hidden dependencies. Parallel runs expose them, and fixing them makes the suite both faster and more honest.

Run only the tests a change can affect

Even a full, fast suite wastes time if a one-line change re-runs everything. In day-to-day development, most of your tests can't possibly be affected by the file you just edited. Running only the tests that touch the changed code - directly or through their dependency graph - shortens feedback time from seconds to nearly instant.

Runners that support "affected" or "related" test selection build a map of which source files each test depends on, then run only the tests downstream of your change. Edit one module and you run maybe twenty tests instead of two thousand, finishing before you've moved your hands off the keyboard.

The trade-off is that affected-only selection trusts the dependency graph, and graphs can miss indirect couplings. So the pattern is two-layered: affected-only for the tight inner loop while you write code, and the full suite at commit or deploy time as a safety net. You get instant feedback most of the time and a guarantee at the moments that matter.

Isolate the slow integration and e2e tests

Some tests are slow for good reasons - they drive a browser, hit a real database, or wait on a queue. You don't want to delete them, but you also don't want them dragging down the suite you run on every change. The solution is to separate them into their own layer that runs at a different cadence.

Tag or fold the slow tests into a separate group, and keep your default "on every change" run pointed at the fast unit layer. The slow layer still runs - just less often, at the moments where its extra coverage justifies the wait.

  • Fast layer on every change. Unit tests and fast integration tests run constantly, keeping the inner loop under a minute.
  • Slow layer at commit or deploy. Full browser and e2e tests run at the gate, where a few extra seconds is a fair price for confidence before shipping.
  • Mark slow tests explicitly. A tag or naming convention makes the split visible, so a slow test never sneaks into the fast layer unnoticed.
  • Mock the real externals. Third-party APIs and network calls belong behind fakes in the fast layer, with a small number of real integration tests reserved for the slow layer.

Set a budget and watch for creep

Suites don't get slow overnight. They get slow one test at a time, each addition adding a few hundred milliseconds nobody notices until the day the whole thing crosses from "instant" to "annoying." The defense is to set a number and treat crossing it as a problem to fix, not a fact to accept.

Pick a budget for the day-to-day run - say, under a minute for the fast layer, ideally under ten seconds. Then make the run time visible so creep can't hide. When a new test pushes you past the budget, that's a signal to investigate: maybe it belongs in the slow layer, maybe it's doing real work it should be mocking, maybe the suite needs another round of parallelization.

  • Set the number. A budget you can state - "the fast suite stays under a minute" - is one you can defend. A vague wish to "keep it fast" loses every argument against a deadline.
  • Measure every run. If you can't see the suite getting slower, you'll only notice once it already hurts. Show the duration where you'll see it.
  • Treat speed regressions like behavior regressions. A suite that doubled its run time deserves the same attention as a broken test, because both erode the habit.
  • Prune without fear. A redundant test that duplicates coverage costs you time on every run forever. Deleting it is a speed improvement, not a loss.

Go deeper: Continuous testing on every commit - how to wire the fast suite into an automated loop so it runs on every change without you lifting a finger.


Frequently asked questions

How fast does a test suite need to be to run on every change?

Aim for sub-minute feedback on the tests that run on every change. Under ten seconds feels instant and you never leave the flow; up to a minute is still comfortable enough to run constantly. Once the day-to-day suite crosses a few minutes, you start avoiding it, and continuous testing quietly stops happening.

What is the test pyramid and why does it matter for speed?

The test pyramid says you should have many fast unit tests at the base, fewer integration tests in the middle, and very few slow e2e tests at the top. It matters for speed because unit tests run in milliseconds while e2e tests run in seconds each. A suite dominated by unit tests stays fast enough to run on every change; one that's too heavy on e2e tests doesn't.

Should I run the whole suite or just the affected tests?

Run only the affected tests in day-to-day development for instant feedback, and run the full suite at commit or deploy time as a safety net. Affected-only runs keep the inner loop fast, while the full run before shipping ensures nothing slipped through a dependency you didn't expect the change to touch.

Sub-minute feedback on every change

Stop choosing between thorough tests and fast ones. Heygents runs your suite automatically on every change and returns results in seconds - so a solo developer keeps continuous testing running without babysitting it or waiting on it.

Try Heygents free →