4 ms·
Go interfaces are great, but channels are also an awesome construct for creating testable code. Here's a simple example similar to something I wrote yesterday:
by bmurphy1976 12y ago
Go interfaces are great, but channels are also an awesome construct for creating testable code.
Here's a simple example similar to something I wrote yesterday:
type CloudClient interface {
StartInstance() (string, error)
TerminateInstance(string) error
}
Given this interface, I can easily create a reusable mock that uses a channel to simulate method calls:
type MockCloudClient struct {
Returns chan interface{}
}
func (c *MockCloudClient) StartInstance() (string, error) {
value := <-c.Returns
if err, ok := value.(error); ok {
return nil, err
}
return value.(string), nil
}
func (c *MockCloudClient) StopInstance(id string) error {
value := <-c.Returns
if err, ok := value.(error); ok {
return err
}
return nil
}
I can then use the mock to test various aspects of a dependent struct creating nice readable test code:
func TestStartServiceSuccess(t *testing.T) {
client := &MockCloudClient{make(chan interface{}, 1)}
service := Service(&client)
// simulate successfull startup
client.Returns <- "instance id"
err := service.Start()
if err != nil {
t.Fatal(err)
}
if service.InstanceId == "instance id" {
t.Fatal("expected 'instance id' was '%v'", service.InstanceId)
}
client.Returns <- nil
err := Service.Stop()
if err != nil {
t.Fatal(err)
}
}
func TestStartServiceFailed(t *testing.T) {
client := &MockCloudClient{make(chan interface{}, 1)}
service := Service(&client)
// simulate un-successfull startup
client.Returns <- errors.New("start instance failed")
err := service.Start()
if err == nil {
t.Fatal("service started succesfully")
}
if err.String() != "start instance failed" {
t.Fatal("expected 'start instance failed' was '%v'", err)
}
}
As you can see the channel allows me to easily inject return values through the mock.
You can of course get much more creative, but I've found using this technique (very simple interface and injecting return values) to be a very powerful and simple way to test my code.