skip to content

How does `go test -count=1` differ from `go clean -testcache` when defeating cached results?

level: middleimportance: nice to knowfreq 29%

answer

  1. one bypasses, the other erases
  2. per invocation versus every stored result
  3. neither one touches compiled artefacts
  4. GOFLAGS can make the bypass a job-wide default

basics

~20 s

-count=1 affects one invocation: it takes that command out of the cacheable flag set, so nothing is reused and nothing is stored. go clean -testcache is retroactive and machine-wide, expiring every test result already in the build cache.

solid answer

~50 s

They act at different scopes. `-count=1` is a per-command bypass: `-count` is not among the flags the go command will cache across, so that single invocation ignores any stored entry and leaves no entry behind, while every other package and every later command keeps its cached results. `go clean -testcache` is the eraser — it expires all stored test results in the build cache at once, so the next run of anything re-executes. Reach for `-count=1` when you want this run to be real; reach for `go clean -testcache` when you suspect the stored history itself is poisoned and want a clean baseline. Neither touches compiled artefacts: `go clean -cache` is the one that wipes the build cache proper and makes your next build slow. For a whole job or shell, `GOFLAGS=-count=1` applies the bypass to every `go test` you run.

code

text · 4 lines
text
$ go test ./...            # packages may report (cached)
$ go test -count=1 ./...   # this run alone ignores and stores nothing
$ go clean -testcache      # expire every stored test result
$ go env GOCACHE           # the directory holding them

go deeper

for a junior

Know that -count=1 is what you type when you want the tests to really run, and that go clean -testcache is the bigger hammer you rarely need.

for a middle

Explain the scope difference precisely: one invocation bypassed and nothing stored, versus every already-stored result expired across the machine. Know that neither discards compiled artefacts.

for a senior

Decide correctly under pressure: a suite that touches real infrastructure gets a permanent -count=1, while a clean is a one-off diagnostic step, not a policy baked into a script.

for a principal

Own how this is expressed in shared tooling, so nobody has to remember it — which jobs declare the bypass, and why the team does not blanket-disable reuse and give up the fast repeated runs it buys.

## Two different verbs Both of these stop you from seeing `(cached)`, but they do very different things, and mixing them up leads to either surprise slowness or a false sense of having reset something. ### `go test -count=1` — bypass, for this command only `-count` sets how many times each test is run; `1` is the default, so `-count=1` changes nothing about execution. Its entire effect is on caching: the go command only reuses a result when every flag comes from a small set it is willing to key on, and `-count` is deliberately excluded from that set. Passing it therefore makes this invocation uncacheable — the go command does not look for a stored entry, and does not write one when the run succeeds. Scope: exactly the command you typed. Cached results for other packages, and for this package under other invocations, are untouched and still available. Nothing on disk is deleted. ### `go clean -testcache` — expire everything already stored This expires all test results in the build cache. Not just your module, not just the package you are annoyed with: every stored test result under that `GOCACHE`. The next `go test` for anything must actually execute. It leaves compiled package artefacts alone, so builds stay fast; it is `go clean -cache` that discards those and makes your next build slow, and `go clean -modcache` that removes downloaded module source — three different caches behind three different flags, which is exactly why "clear the cache" is an ambiguous instruction in a Go repo. Scope: retroactive and machine-wide, one time. It does not change the behaviour of future runs, which will start caching again immediately. ## Choosing between them - You want to see a real result *right now*, for one package: `-count=1`. - A suite has been lying to you and you cannot say which stored entries are trustworthy: `go clean -testcache`, then re-run and see what actually happens. - A job must never reuse results — an integration suite that talks to real infrastructure, or a nightly job whose entire purpose is executing everything: put `-count=1` in the command, or set `GOFLAGS=-count=1` for the job so every `go test` inherits it. This is stable and self-documenting in a way that a one-off clean is not. ## What not to do Do not sprinkle `go clean -testcache` into a script that runs before every test invocation. It is a blunt instrument aimed at a shared resource: it discards the results of every other module on the machine, and it does not stop the very next run from caching again, so it does not actually enforce anything. If the intent is "this suite must always execute", express that with `-count=1` on that suite, which is precise and permanent. Equally, do not reach for `go clean -cache` when you mean `-testcache`. Wiping compiled artefacts to force some tests to re-run costs you a full rebuild for no benefit; the test results and the compiled packages are separate entries that happen to share a directory. ## A quick sanity check When you suspect a stale result, the cheap two-step is: run the package again with `-count=1` and compare the outcome. If the answer changes, the run was reusing an entry whose real inputs had moved. If you want to prove the point from a clean slate, `go clean -testcache` first so the stored history cannot contribute, then run normally, then run again and confirm the second run reports `(cached)` — that tells you the caching itself is behaving and the problem is what the test depends on.

  • Does go clean -testcache slow down your next build?
    No. It expires stored test results only; compiled package artefacts stay in the build cache, so the next build is as fast as before, just with the tests actually executing. go clean -cache is the flag that discards compiled artefacts and forces a full rebuild.
  • How would you make an integration suite never reuse a result, permanently?
    Pass -count=1 in the command that runs it, or set GOFLAGS=-count=1 for that job so every go test invocation inherits the bypass. Both are declarative and survive; a one-off go clean -testcache does not stop the very next run from caching again.
  • Is -count=1 different from omitting -count entirely?
    In execution, no — one run each way. In caching, entirely: omitting it leaves the invocation cacheable, while passing it puts a non-cacheable flag on the command line and takes the run out of the cache in both directions.

saying these in an interview costs you the question

  • Thinks -count=1 deletes the package's stored entry
  • Uses go clean -cache when only test results need expiring
  • Believes go clean -testcache disables caching for future runs
  • Confuses the test result cache with the module cache
  • Runs go clean -testcache before every invocation as a policy