1. 程式人生 > >Yet another tool to mock interfaces in Go

Yet another tool to mock interfaces in Go

Yet another tool to mock interfaces in Go

https://itnext.io/yet-another-tool-to-mock-interfaces-in-go-73de1b02c041

As a powerful tool, unit tests can give the ability to check every aspect of the code behavior. If you will keep the idea about the need for code testing in mind, you will always write sustainable and maintainable code and put integrity on top of it. Well designed code which depends on abstractions is easy to test, so code testability also can serve as an indicator of its quality.

If you have already tried to test code in Go, you probably know how useful interfaces can be. Go standard library provides you with the bunch of interfaces which you’re able to use in your code and the most part of them contains just a single method.

Go also has a supplementary framework created to help mock interfaces and a bunch of other community-driven packages which share similar functionality. Most of them give the ability to generate struct which is implements given interface, this is very useful if an interface is large or it embeds other interfaces but isn’t it too much when an interface has a single method?

The most amazing part about interfaces in Go is that they’re satisfied implicitly. Any type satisfies an interface simply by providing methods whose signature matches the interface declaration. This type could be even a function and if you’re familiar with package net/http you might already saw one of that types also called adapters

.

 

As you can see, adapter itself is a function type with the same signature as the interface method declaration and it implements an interface by calling itself in the corresponding method. This adapter allows implementing Handler by any function with the appropriate signature. It comes as a generic tool to mock interfaces and looks very handy in table driven tests. For example, here’s the code which should be tested:

 

With the usage of the adapter, unit tests might look something like this:

 

Writing such adapters can be really annoying, so I’ve decided to write a tool for generation and called it adapt, this tool generates an adapter for a specified interface and prints it in output. All you need is to pass package name and interface name to generate it.

$ adapt io Reader
type readerFunc func([]byte) (int, error)

func (f readerFunc) Read(p []byte) (int, error) {
	return f(p)
}

You also can call adapt inside a package folder to generate adapter for some of the package interfaces.

$ cd $GOPATH/src/github.com/x/execute Doer
$ adapt Doer
type doerFunc func() (int, error)

func (f doerFunc) Do() (int, error) {
	return f()
}

It comes with a handy vim plugin which gives functionality to generate adapter inside the vim.

Hopefully, you will find it useful.