Files
teamai-test/.teamai/skills/common/golang-project-layout/references/testing-layout.md
T

5.1 KiB

Tests, Benchmarks, and Examples

File Naming Conventions

Go uses suffix-based naming for test-related files:

Suffix Purpose Build Tag
_test.go Tests Not included in normal builds
_bench_test.go Benchmarks Not included in normal builds
_example_test.go Examples that verify output Not included in normal builds
No suffix Regular code Included in all builds

Where to Place Tests

Co-locate tests with the code they test:

internal/
├── handler/
│   ├── handler.go          # Production code
│   ├── handler_test.go     # Tests for handler
│   └── handler_bench_test.go  # Benchmarks (optional)
├── service/
│   ├── service.go
│   └── service_test.go
└── model/
    ├── user.go
    └── user_test.go

pkg/
└── logger/
    ├── logger.go
    └── logger_test.go

Key principles:

  • Tests live in the same package as the code (e.g., package handler)
  • Test files are in the same directory as the code they test
  • Use _test.go suffix for all test files

Test Package Options

When writing tests, you have two options for the package declaration:

Option 1: Same package (white-box testing)

package handler  // Same package, can access unexported

import "testing"

func TestHandler(t *testing.T) {
    // Can access unexported functions and types
    internalFunction()
}

Option 2: Package with _test suffix (black-box testing)

package handler_test  // Different package, only exported API

import "testing"

func TestHandler(t *testing.T) {
    // Can only access exported functions and types
    handler.PublicMethod()
}

When to use each:

  • Use same package for unit tests that need to test internals
  • Use _test suffix for integration/behavioral tests

Benchmarks

Benchmarks use the _bench_test.go suffix and contain functions with the Benchmark prefix.

Examples

Examples serve two purposes: documentation and verification.

In libraries - use *_example_test.go files:

pkg/
└── logger/
    ├── logger.go
    ├── logger_test.go
    └── logger_example_test.go     # Examples

Example function format:

package logger

import "fmt"

func ExampleLogger_Info() {
    log := New()
    log.Info("processing started")
    log.Info("processing complete")
    // Output:
    // INFO: processing started
    // INFO: processing complete
}

Key points:

  • Example functions must start with Example
  • The // Output: comment verifies the output
  • Examples are runnable tests: go test will fail if output doesn't match
  • godoc displays examples as documentation
  • File name format: {package}_example_test.go (e.g., logger_example_test.go)

For executable examples (standalone demo programs):

examples/
└── basic-usage/
    └── main.go                    # Executable example

Test Utilities

When you have shared test helpers, use a dedicated package:

test/
└── testutils/
    ├── mock.go
    └── fixtures.go

Or use the internal/testutil pattern:

internal/
└── testutil/
    ├── mock.go
    └── fixtures.go

Test Fixtures

Fixtures are test data files used across multiple tests. Use one of these patterns:

Option 1: Local testdata directory (package-specific fixtures)

internal/
└── handler/
    ├── handler.go
    ├── handler_test.go
    └── testdata/
        ├── users.json
        ├── request_valid.json
        └── request_invalid.json

Option 2: Global test directory (shared across packages)

test/
└── fixtures/
    ├── users.json
    ├── products.json
    └── responses/
        ├── success.json
        └── error.json

Option 3: Embedded fixtures (Go 1.16+, use //go:embed)

internal/
└── handler/
    ├── handler.go
    ├── handler_test.go
    └── testdata/
        └── users.json

Important notes:

  • Go ignores the testdata directory when building regular packages
  • Use testdata/ for package-specific test data
  • Use test/fixtures/ for cross-package shared fixtures
  • Don't put .go files in testdata/ - they will be ignored

Running Tests

go test ./...                    # Run all tests
go test ./internal/handler       # Test specific package
go test -v ./...                 # Verbose output
go test -race ./...              # Race detection
go test -cover ./...             # Coverage report
go test -short ./...             # Skip long-running tests

Test File Summary

File Type Suffix Package Purpose
Test *_test.go package X or package X_test Unit/integration tests
Benchmark *_bench_test.go Same as code Performance tests
Example (godoc) *_example_test.go Same as code Documentation + verification
Executable example No suffix package main Standalone demo programs
Test utilities *_test.go package testutil Shared test helpers