This is a quick sketch of how I think terminology applies to the various kinds of mocking and test doubles that apply in Go.
In practice, the most effective way to mock things in Go is to use an interface, and then to substitute a specialized testing implementation in place of a real one. Wherever a substitute is used, I think this should be called a "double".
There is one specialization of a "double" and that is a "fake" implementation. Fakes can often have real world uses, e.g: "RamDiskDatabase", but are typically substituted in order to get real world behavior with some cost eliminated.
Otherwise, all other terminology applies to methods.
type Vehicle interface {
func Drive(int distance) error
func Refuel(int amount) error
func Accelerate() error
func Stop() error
}
// A real implementatiom
type Car struct {
...
}
// A double which is a fake
type CarWithNoGasConsumption struct {
}
func (c *CarWithNoGasConsumption) Refuel(int amount) error {
// no-op
return nil
}
... more impl
// A double which has a mix of mocks/stubs/spies and proxies
type CarDouble struct {
realCar *Car
accelCount int
mocker MockImpl
}
// A stub
func (c *CarDouble) Refuel(int amount) error {
throw "Refuelling this car is an exception"
}
// A spy
func (c *CarDouble) Accelerate(int amount) error {
// Record some information about the call
accelCount += 1
// TODO: Forward to real impl?
return nil
}
// A mock
func (c *CarDouble) Stop() error {
// Record call, test must later make sure all expected calls were made
c.mocker.RecordExpectedCall("Stop()")
// ...
}
// A proxy
func (c *CarDouble) Refuel(int amount) error {
// Forward call to a real object
return c.realCar(amount)
}