Skip to content

How to Debug Go Test Failures

DodaTech 2 min read

In this tutorial, you'll learn about How to Debug Go Test Failures. We cover key concepts, practical examples, and best practices.

The Problem

You run go test and see:

--- FAIL: TestCalculateTotal (0.00s) main_test.go:25: expected 100, got 99 FAIL


The test failed, but you need more information to understand why and fix the code.

## Quick Fix

### Step 1: Run with verbose output

```bash
go test -v ./...

Expected:

=== RUN   TestCalculateTotal
    main_test.go:25: expected 100, got 99
--- FAIL: TestCalculateTotal (0.00s)
=== RUN   TestParseInput
--- PASS: TestParseInput (0.00s)
FAIL

-v prints every test name and its result, not just failures.

Step 2: Run a specific test

go test -v -run TestCalculateTotal ./...

The -run flag matches a regex against test function names. This runs only matching tests, saving time in large suites.

Step 3: Run with race detection

go test -race ./...

Expected:

==================
WARNING: DATA RACE
Read at 0x00c0000a0f0 by goroutine 8:
  myapp.TestConcurrentAccess()
      /project/main_test.go:42 +0x45
==================

The race detector finds concurrent access bugs that would otherwise appear randomly in production.

Step 4: Show test coverage

go test -cover ./...

Expected:

ok      myapp   0.123s    coverage: 78.5% of statements

Step 5: Generate a coverage report

go test -coverprofile=coverage.out ./...
go tool cover -html=coverage.out -o coverage.html

Open coverage.html in a browser. Green lines are covered, red lines are not.

Step 6: Run tests with a timeout

go test -timeout 30s ./...

Tests that hang beyond the timeout are killed with a stack trace. The default timeout is 10 minutes.

Step 7: Print logs from tests

go test -v ./... 2>&1

If your test uses t.Log() or fmt.Println, the output only appears with -v.

Step 8: Run tests in short mode

go test -short ./...

In the test file:

func TestIntegration(t *testing.T) {
    if testing.Short() {
        t.Skip("skipping integration test in short mode")
    }
}

Use -short during development to skip slow integration tests.

Step 9: Run tests repeatedly to find flakes

go test -count=5 -run TestFlaky ./...

The -count flag runs the same test multiple times. Flaky tests that fail intermittently become visible.

Alternative Solutions

Use go test -json ./... for structured output that can be parsed by CI tools and IDEs.

Prevention

  • Write table-driven tests to cover edge cases systematically.
  • Run go test -race ./... in CI to catch data races early.
  • Keep unit tests independent and parallelizable.
  • Aim for at least 80% coverage on critical business logic.
  • Use test coverage thresholds in CI to prevent coverage regression.

Common Errors

Test hanging indefinitely: If a test does not complete, it may be blocked on a channel or network call. Add a timeout: go test -timeout 5s. For individual tests, use ctx, cancel := context.WithTimeout(...).

Flaky tests: A test that passes sometimes and fails others is usually caused by shared state or race conditions. Run with -race and -count=10 to reproduce.

Missing test files: Tests must be in files named *_test.go. A file named helper_test.go is discovered, but test_helper.go is not.

Testing private functions: Go tests in the same package can access private functions. If the test is in package myapp_test (external test package), it only sees exported symbols. Switch to package myapp to test internals.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro