liveBook · Manning

Stub

As explained in Learn Go with Pocket-Sized Projects

A stub is a minimal test double that provides a simplified implementation of a dependency, typically with predetermined behavior.

A stub replaces a dependency with a small implementation that returns predetermined results. Use one when the code under test needs input or a service, but the real dependency is unavailable or would make a unit test cumbersome. section 6.5 section 6.5.5

Supply player input without a player

A game’s `ask` method reads from a `bufio.Reader`. Passing `strings.NewReader(tc.input)` to the game constructor supplies test input instead of waiting for someone at the terminal. Test cases include five-rune guesses in several scripts and an invalid guess followed by a valid one. section 5.1.2

For a service dependency, define the smallest interface the caller needs, then implement it in the test. A currency converter needs only `FetchExchangeRate`; its stub can return a chosen rate or error. This also avoids passing `nil`, which causes a panic when the converter calls the dependency. section 6.5.5

Listing 6.52 convert_test.go: Stubbing the dependency
// stubRate is a very simple stub for the exchangeRates.
type stubRate struct {
    rate money.ExchangeRate
    err  error
}

// FetchExchangeRate implements the interface exchangeRates with the same 
// signature but fields are unused for tests purposes.
func (m stubRate) FetchExchangeRate(
    _, _ money.Currency, #1
) (money.ExchangeRate, error) {
    return m.rate, m.err
}

The exchange-rate stub stores a rate and an error, then returns them from its interface method; the currency arguments are unused. section 6.5.5

Keep an interface narrow at an HTTP handler boundary, too. A game-creation handler needs only a repository method that adds a game. A one-method stub lets its test call the handler without connecting to an external database. section 8.4.3

Listing 8.31 newgame/handler_test.go: Stubbing the repository
func TestHandle(t *testing.T) {
    handleFunc := Handler(gameAdderStub{}) #1

    req, err := ...
    // ...

    handleFunc(recorder, req) #2

    assert...
}

type gameAdderStub struct { #3
    err error
}

func (g gameAdderStub) Add(_ session.Game) error {
    return g.err
}

The handler test passes `gameAdderStub{}` to `Handler`; the stub’s `Add` method returns its configured error. section 8.4.3

A stub supplies behavior but does not verify how it was called. When a test must check call counts or arguments, use a mock instead; generated mocks are an option when hand-written test doubles become less convenient. section 6.5.5 section 10.4

How Learn Go with Pocket-Sized Projects covers it

How deep it goes
Shows hand-written stubs with predetermined results and contrasts them with mocks that verify calls; defers larger mock implementations to generators.
Examples
Uses `strings.NewReader` for game input, a configurable exchange-rate stub, and a one-method repository stub for an HTTP handler.
What it assumes
Assumes familiarity with Go structs, methods, interfaces, and tests while defining what stubbing does.
What you can do after
Build it from scratch as a small Go implementation of an interface that returns values selected for a unit test.
How it connects
Connects stubs to interfaces, dependency injection, unit testing, HTTP handlers, and mocks.

Also explained in

Compare how 10 books explain stub →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Learn Go with Pocket-Sized Projects. The section links point to the parts of the book it draws on.