Test Doubles: Mocks and Stubs
Interfaces for testability and dependency injection
Test Doubles: Mocks and Stubs is a free Go Academy lesson on CoddyKit — lesson 3 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Go Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
Test doubles overview
A test double replaces a real dependency in tests. Types: stub (returns canned responses), mock (verifies interactions), spy (records calls), fake (working in-memory impl).
Interfaces enable test doubles
Design functions to accept interfaces rather than concrete types. In production, pass the real implementation; in tests, pass a test double.
type UserStore interface {
FindByID(id int) (*User, error)
}
func GetUser(store UserStore, id int) (*User, error) {
return store.FindByID(id)
}Manual stub
A stub is a simple struct that implements an interface and returns pre-configured values:
type stubStore struct{ user *User; err error }
func (s *stubStore) FindByID(_ int) (*User, error) { return s.user, s.err }
// In test:
store := &stubStore{user: &User{Name: "Alice"}}
result, _ := GetUser(store, 1)Manual mock
A mock records calls and asserts on them:
type mockStore struct {
called bool
gotID int
user *User
}
func (m *mockStore) FindByID(id int) (*User, error) {
m.called = true; m.gotID = id
return m.user, nil
}
// Assert: if !mock.called { t.Error(...) }testify/mock
The testify/mock package generates or writes mock objects with call expectations and return value configuration:
type MockStore struct { mock.Mock }
func (m *MockStore) FindByID(id int) (*User, error) {
args := m.Called(id)
return args.Get(0).(*User), args.Error(1)
}
// In test:
m := new(MockStore)
m.On("FindByID", 1).Return(&User{}, nil)
m.AssertExpectations(t)gomock
go.uber.org/mock/gomock (formerly golang/mock) generates mocks from interfaces. Use mockgen CLI to generate; use EXPECT() to set expectations.
Fake
A fake is a working, in-memory implementation. E.g., an in-memory user store that stores users in a map. Fakes are heavier to write but more realistic and less brittle than mocks.
type fakeStore struct{ users map[int]*User }
func (f *fakeStore) FindByID(id int) (*User, error) {
u, ok := f.users[id]
if !ok { return nil, ErrNotFound }
return u, nil
}httptest for HTTP clients
net/http/httptest provides an in-process HTTP test server and recorder — the standard fake for HTTP-based dependencies.
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(User{Name: "Alice"})
}))
defer ts.Close()When to use each double
Stub: simple fixed response. Mock: verify call count/args. Fake: complex behaviour. Avoid over-mocking — fakes and real components in integration tests are more reliable.
Avoiding fragile tests
Mocks that assert exact call order or argument values become fragile as the implementation evolves. Prefer stubs with output assertions or fakes when possible.
Interface discovery
Extract interfaces after identifying the concrete type's surface used by callers (ISP). Go supports implicit interface satisfaction — no modification of the concrete type needed.
Quick Check
What is the main difference between a stub and a mock?
Recap: Test Doubles
Key points:
- Design against interfaces to enable test doubles
- Stub: returns canned data; Mock: verifies interactions
- httptest for HTTP; in-memory fakes for storage
- Avoid over-mocking — prefer fakes for complex behaviour
Frequently asked questions
Is the “Test Doubles: Mocks and Stubs” lesson free?
Yes — the full text of “Test Doubles: Mocks and Stubs” is free to read here on the web, and the Go Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Go Academy course, upgrade to CoddyKit PRO.
What will I learn in “Test Doubles: Mocks and Stubs”?
Interfaces for testability and dependency injection You practise Go Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Go Academy?
No prior experience is required. Go Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 3 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Test Doubles: Mocks and Stubs” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Go Academy lesson?
Yes. Every Go Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- Writing Unit Tests with testing
- Table-Driven Tests
- Test Doubles: Mocks and Stubs
- Test Coverage and testify