It takes more code to mock a struct in Go than other OOP languages that support full late binding.
This code must remain untouched since its taken from a 3rd party:
type Car struct {
Name string
}
func (c Car) Run() {
fmt.Println("Real car " + c.Name + " is running")
}
type CarFactory struct {}
func (cf CarFactory) MakeCar(name string) Car {
return Car{name}
}
Since Go only supports late binding on interface, I had to make Transport
receive an interface as a parameter instead of a struct:
type ICar interface {
Run()
}
type ICarFactory interface {
MakeCar(name string) ICar
}
func Transport(cf ICarFactory) {
...
car := cf.MakeCar("lamborghini")
car.Run()
...
}
And here are the mocks:
type CarMock struct {
Name string
}
func (cm CarMock) Run() {
fmt.Println("Mocking car " + cm.Name + " is running")
}
type CarFactoryMock struct {}
func (cf CarFactoryMock) MakeCar(name string) ICar {
return CarMock{name}
}
Now I can easily use the mock Transport(CarFactoryMock{})
. But when I try to call the real method Transport(CarFactory{})
, the go compiler shows me the following errors:
cannot use CarFactory literal (type CarFactory) as type ICarFactory in argument to Transport:
CarFactory does not implement ICarFactory (wrong type for MakeCar method)
have MakeCar(string) Car
want MakeCar(string) ICar
As the message says, MakeCar
function from the interface returns an ICar
, but the real MakeCar
returns a Car
. Go doesn’t allow that. To walk around this problem I had to define a wrapper to manually convert Car
to ICar
.
type CarFactoryWrapper struct {
CarFactory
}
func (cf CarFactoryWrapper) MakeCar(name string) ICar {
return cf.CarFactory.MakeCar(name)
}
Now you can call the Transport
function like this: Transport(CarFactoryWrapper{CarFactory{}})
.
Here is the working code https://play.golang.org/p/6YyeZP4tcC.