I am trying to avoid using an interface because my use cases do not require it (similarly mentioned in https://www.ardanlabs.com/blog/2016/10/avoid-interface-pollution.html). However, to create a mock (using testify
), wouldn't I need an interface to mock? I could create one, but it seems tedious. All the places my code is used would require writing interfaces for their mocking, not for their actual usage. Is there a workaround?
If the only possible use of an interface is for testing, I agree, that's probably a bad interface, and you should avoid that.
The best way is to refactor your system to rely on a small, useful interfaces rather than one-off "mocks" of over-complicated structs. A very good example of this is the net.Listener
interface. A system built on top of net.Listener
is easy to mock, yes, but that's not why you implement net.Listener
. You use the interface because it lets you swap in many possible implementations, one of which happens to be for testing.
Another powerful approach is chain together functions rather than hard-coding functionality as methods. http.HandlerFunc
is a great example of this that also demonstrates great interface design. See the many "click-together" functions that return a http.Handler
, rather than one, massive "Handler" struct that you'd then have to mock for testing. This is Go at its best IMO.
Remembering that functions are first-class in Go, you can get a lot of flexibility by passing and returning functions rather than tying them to interfaces. When you do that, you also can bundle those together as a struct. This can give a lot of power that also happens to be useful for testing. For example see, tls.Config
which allows you to include your own GetCertificate
function (among others). But the tls.Config
struct also has sensible defaults so you don't have to configure every piece every time. By passing a specialized version of tls.Config
, you can test TLS functionality without "mocking" anything.
The consistent theme here is to make your system flexible about its implementations, and as a nice side-effect, that makes testing easier. In my experience, this is a much better way to think about the problem than mocking.