Paymahn Moghadasian
Paymahn Moghadasian

Reputation: 10329

How to mock docker ApiClient in Golang?

I've implemented a wrapper for the Docker ApiClient like so

type DockerClient struct {
    cli client.APIClient
}

I've also defined my own interface for interacting with Docker like so

type Dockerer interface {
    Init() error
    CreateContainer(ctx context.Context, imageName string) (string, error)
    RunCommand(ctx context.Context, containerId string, command string) (string, int, error)
    StopContainer(ctx context.Context, containerId string) error
}

DockerClient implements the functions in the Dockerer interface like so:

func (d *DockerClient) Init() error {
    //...
}

func (d *DockerClient) CreateContainer(ctx context.Context, imageName string) (string, error) {
    //...
}


func (d *DockerClient) RunCommand(ctx context.Context, containerId string, command string) (string, int, error) {
    //...
}

func (d *DockerClient) StopContainer(ctx context.Context, containerId string) error {
    //...
}

This has made it easy to test the components of my code that need to interface with Docker because I can generate a mock for my Dockerer interface and dependency inject that mock.

However, now I'd like to write tests for the actual implementation of the DockerClient wrapper. It seems like no mocks are provided for ApiClient by the docker package. Is there a canonical pattern for writing tests when the package I need to use doesn't provide mocks? Is there a way to get mockery to generate mocks for library interfaces?

Upvotes: 3

Views: 1365

Answers (1)

Pratik Deoghare
Pratik Deoghare

Reputation: 37172

client.APIClient is an interface. You can embed that interface in a struct. Yes you can do this. You can embed interface inside struct. Then you selectively implement methods that you need for test. This way you don't have to implement every single method from the interface. It will impractical to implement all the methods that client.APIClient provides because it embeds interface that embeds whole lot of interfaces. See.

Like this,


type mockCli struct{
   client.APIClient
}

func (mockCli) ClientVersion() string {
   return "5"
}


func TestA(t *testing.T) {
   dc := &DockerClient{
      cli: new(mockCli),
   }

   ...

   dc.Init() 
   // This will print "5" if your Init has 
   // fmt.Println(d.cli.ClientVersion())) somewhere.

   // If you call any other method of cli, you get panic. 
   // A good thing. It will inform you that you are using 
   // some method that you don't have on mockCli. You 
   // just add it then. 
   
}

Upvotes: 4

Related Questions