Cool makefile target for Golang mocks generation

One thing I found a bit annoying when I first started coding in Go is that if you want to unit-test your code built around interfaces, you always need to write the mocks that implement interfaces.

Unlike Java, there is no proxy magic like mockito that allows you to state ‘I want a mock that implements this interface’ right from your unit test, and the magic creates the object for you.

Nope. In Go, thou shalt code a mock that satisfies this interface and implements every single one of its functions.

Luckily, there are libraries to generate mocks: personally, I use vektra’s mockery.

It is pretty simple to use, decently documented, and it does the job pretty well. Just be aware that on Windows machines, you might need to manually fix imports of vendored libraries.

Anyways, it is no magic wand: from your unit test, you still need to instruct the mock on how to behave when called.

If you like the idea behind it and want to give it a try, I’d suggest you to first play with it just to generate the mock for one or two interface.

And if you like what you saw and want the generation automated at project level, you can check out this Makefile target I use at (don’t be scared by the big command – explanation will follow 😃):

.PHONY: update-mocks
    go get -u

    go list -f '{{.Dir}}' ./... \
    | grep -v "$(notdir $(CURDIR))$$" \
    | xargs -n1 ${GOPATH}/bin/mockery \
       -inpkg -case "underscore" -all \
       -note "NOTE: run 'make update-mocks' from bookkeeping-worker top folder to update this file and generate new ones." \

So, let’s take a deep breath and dive in the commands:

  • Lines 1 and 2 declare the target ‘update-mocks’ – to run it, you’ll then do ‘make update-mocks’.
  • Line 3 downloads (or updates) the mockery tool
  • Lines 5 and 6 list all folders that contain go files – I don’t run recursively on ‘.’ because that would cause mockery to get into vendor folders
  • Line 7 calls mockery for each folder
  • Line 8 adds three options, for, respectively:
    • generating mocks in the same package as the mocked interfaces instead of creating a ‘mocks’ dedicated package (it is generally safer to use this option even though it’s not default)
    • naming mock files in snake_case
    • generating mocks for all interfaces found
  • Line 9 adds a note in generated files to explain developers how this file was generated, and how to update it

If you like it, use and customise it to your needs…. if yours is a small project, you can simplify this command a lot: for example, for projects with no vendor folders, the second command can become:

    ${GOPATH}/bin/mockery \
      -inpkg -case "underscore" -all \
      -note "NOTE: run 'make update-mocks' from bookkeeping-worker top folder to update this file and generate new ones." \
      -dir .