You are viewing a free preview of this lesson.
Subscribe to unlock all 10 lessons in this course and every other course on LearningBro.
Go comes with a comprehensive built-in toolchain that handles formatting, testing, vetting, building, and dependency management. This lesson covers the package system, the testing framework, and the essential Go tools every developer should know.
Every Go file belongs to a package:
package math // this file belongs to the "math" package
| Concept | Description |
|---|---|
| Package | A directory of Go files compiled together |
| main package | Special — defines an executable program |
| Exported names | Start with an uppercase letter (e.g., Println) |
| Unexported names | Start with a lowercase letter (e.g., helper) — private to the package |
myproject/
├── go.mod
├── main.go # package main
├── server/
│ ├── server.go # package server
│ └── server_test.go # tests for package server
├── model/
│ └── user.go # package model
├── handler/
│ ├── user.go # package handler
│ └── user_test.go
└── internal/
└── auth/
└── auth.go # package auth (only importable within myproject)
The internal directory restricts package visibility:
internal/ can only be imported by code rooted at the parent of internal/import (
"fmt" // standard library
"net/http" // standard library (nested)
"github.com/gorilla/mux" // third-party
"myproject/model" // local package
)
import (
"fmt"
stdhttp "net/http" // alias to avoid collision
_ "github.com/lib/pq" // blank import — run init() only
. "math" // dot import — use Sqrt() without math.Sqrt()
)
| Import Style | Use Case |
|---|---|
| Normal | import "fmt" — most common |
| Alias | import alias "pkg" — avoid name collisions |
| Blank | import _ "pkg" — run init() for side effects (e.g., database drivers) |
| Dot | import . "pkg" — rarely used outside tests |
Go has a built-in test framework — no third-party library required.
Create a file ending in _test.go:
// math_test.go
package math
import "testing"
func TestAdd(t *testing.T) {
result := Add(2, 3)
if result != 5 {
t.Errorf("Add(2, 3) = %d; want 5", result)
}
}
| Rule | Description |
|---|---|
| File name | Must end in _test.go |
| Function name | Must start with Test |
| Parameter | t *testing.T |
| Package | Same package (white-box) or package_test (black-box) |
go test # test current package
go test ./... # test all packages recursively
go test -v # verbose output
go test -run TestAdd # run specific test(s) matching regex
go test -count=1 # disable test caching
go test -race # run with race detector
go test -cover # show coverage percentage
The idiomatic Go testing pattern:
func TestAdd(t *testing.T) {
tests := []struct {
name string
a, b int
expected int
}{
{"positive", 2, 3, 5},
{"zero", 0, 0, 0},
{"negative", -1, -2, -3},
{"mixed", -1, 5, 4},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := Add(tt.a, tt.b)
if result != tt.expected {
t.Errorf("Add(%d, %d) = %d; want %d",
tt.a, tt.b, result, tt.expected)
}
})
}
}
t.Run creates named subtests that can be run individually:
go test -run TestAdd/positive
func BenchmarkAdd(b *testing.B) {
for i := 0; i < b.N; i++ {
Add(2, 3)
}
}
Run benchmarks:
go test -bench=.
go test -bench=BenchmarkAdd -benchmem
Subscribe to continue reading
Get full access to this lesson and all 10 lessons in this course.