Cache in Go: An Enemy of Testing? Understanding Force Retesting

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Why Does Go Hide Test Results? (And How It Breaks Your Workflow)

\n\n

Imagine: you're writing Go, you run go test, you see a green checkmark... but something went wrong. You fixed a bug, run the tests again—and you get a green light again. But the bug is still there! Sound familiar? Welcome to the world of Go test caching.

\n\n

Go is a language that loves speed. To avoid running the same tests ten times over, the compiler caches results. This sounds convenient until you encounter a situation where the Go test cache starts working against you. This is especially painful for developers working with integration tests, the file system, or external APIs.

\n\n

In this article, we'll break down two approaches to solving the problem: force retesting and completely disabling the test cache. You'll learn when to use which approach and get working code examples.

\n\n

How Test Caching Works in Go

\n\n

Before we break things, let's understand how it works. Go caches test results based on a hash of:

\n
    \n
  • Source code (.go files)
  • \n
  • Test files
  • \n
  • Environment variables
  • \n
  • Compilation flags
  • \n
\n\n

If nothing has changed—Go simply shows the cached result. Fast? Yes. Dangerous? Absolutely! Imagine your test depends on time, random numbers, or an external service. The cache will say, "All good!" even though the test would have failed long ago.

\n\n
// Example of a test that will be falsely green due to the cache\nfunc TestCurrentTime(t *testing.T) {\n    now := time.Now()\n    if now.Year() != 2024 {\n        t.Errorf("Year should be 2024, got %d", now.Year())\n    }\n}
\n\n

Run this test once—it passes. Change the year to 2025 in the code? The cache will still show the old result. And you'll be left wondering why CI is failing while everything "works" locally.

\n\n

Approach 1: Force Retesting

\n\n

The most popular way to fight the cache is the -count=1 flag. This is force retesting in its pure form. It tells Go: "Don't trust the cache, run the test again from scratch."

\n\n
// Run with force retesting\ngo test -count=1 ./...
\n\n

Why -count=1 and not -count=0? Because -count specifies the number of times to run the test. 1 is the minimum value that disables the cache. 0 simply won't run anything.

\n\n

When to Use Force Retesting

\n
    \n
  • Integration tests that access a database or API
  • \n
  • Tests with random data (fuzz tests, UUID generation)
  • \n
  • Tests that depend on time (timeouts, dates)
  • \n
  • Local development when you frequently change code
  • \n
\n\n

Example: Integration Test with Force Retesting

\n\n
package db_test\n\nimport (\n    "testing"\n    "time"\n)\n\nfunc TestDatabaseConnection(t *testing.T) {\n    // This test depends on a live server\n    // Without -count=1 it might show an old result\n    db := connectToDatabase()\n    if err := db.Ping(); err != nil {\n        t.Fatalf("Failed to connect: %v", err)\n    }\n    \n    // Simulate a time delay\n    time.Sleep(100 * time.Millisecond)\n    if err := db.Query("SELECT 1"); err != nil {\n        t.Errorf("Query failed: %v", err)\n    }\n}
\n\n

Run it: go test -count=1 -v ./db/. Now every run is honest. But there's a catch: force retesting doesn't solve the problem globally. If you forget the flag—the cache comes back.

\n\n

Approach 2: Completely Disabling the Test Cache

\n\n

The second option is radical. You simply tell Go: "Don't cache anything." This is done via the environment variable GOCACHE=off or the flag -count=1.

Blogs

Book Recommendations