Kinbiko

How I Built a Go Mocking Framework in 5 Days

March 28, 2020

Some technical knowledge assumed.

This past week I’ve had the privilege of having a Hack Week where I work, where we can work on whatever we wanted. I ended up building Mokku — a mocking framework for Go that gets out of your way.

Key features

  • Invisible: No hard (import) or soft (//go:generate) dependencies to add to your codebase.
  • Unintrusive: Can be included in any developer’s workflow. Doesn’t dictate or enforce how you use it after it’s written.
  • Unassuming: Doesn’t care about package paths or even if your file compiles. All it wants is an interface.
  • Vanilla: It’s basically a shortcut to generating the mocks you’d probably write yourself if you wrote the mocks manually.

I’ve been wanting to write this mocking framework for a while now. So when I finally had the opportunity to work on this full time for a week, I implemented all the techniques and processes I personally prefer (I was developing this project on my own) and genuinely had a good time working on this. You can check out the project in its entirety on GitHub, so I won’t go into the details of how to use it etc. here.

Instead, I’d like to share how the development process went. As opposed to most technical blog posts, and indeed most of my own blog posts, this won’t be an article where I try and tell you how you should do things. I’m just going to share what I did, and some of my thoughts around how things went.

You know, like a blog.

But first, a bit of background.

GoMock?! Go away

I had two main sources of ‘fuel’ so to speak, for delivering Mokku. The first was the frustration I’ve had when working with GoMock. Its super terse error messages, annoying gotchas and things to remember left me with a strong desire to make something SIMPLE.

The second source of fuel is more of an inspiration. Mat Ryer’s Moq mocking framework ticks most of what I was looking for in a mocking framework, and then some. In fact, the usage of Mokku is very similar to how you use Moq. I chose to drop some of the bells and whistles that come with Moq (maybe I’ll incorporate them as command line flags down the line), and went with what in my opinion is an even simpler approach. For example, instead of storing all arguments that have been passed to the mocks by default (and having them be safe for concurrent access), I opted to defer the implementation of this logic to the users (see what I did there? … I’ll see myself out).

Day 1: Planning

I spent the first day quickly putting together a rough project plan and product and engineering designs in the Wiki of the GitHub project (you can still find it there). I knew from the start that the purpose of doing these planning activities wasn’t to know exactly how I was going to do things. It was more to see the scope of the project that I could fit into this one week I had available to me. Appetite, not estimate. Luckily, my gut feel told me I could get quite a fair bit done in the allotted time, without skimping out on quality.

As part of doing the quick engineering design, I dove deeper into how Moq worked under the hood, and was able to steal some of the ideas used. The main idea I stole was to use the text/template to generate the mocked structs. In hindsight this is an obvious choice, I think I had just forgotten about this package’s existence. It is somewhat overshadowed by its HTML counterpart.

In terms of actual product value, by the end of the first day I barely managed to scrape together a skeleton with a dummy test running in CI. But that’s fine. The tree still stands, but the axe is sharp.

Day 2: Parsing

I spent the second day doing the initial version of a ‘parser’, that would read a given interface definition given as []byte, and identify its comprising components. I used test driven development in this endeavour as I had pretty good idea of what I wanted to get out of it (I knew the input I’d get, I knew the output I wanted), but didn’t actually know how to implement it yet. I initially thought I could use the go/parser package from the standard library, but this wasn’t quite as flexible as I needed it to be. After looking around for a bit longer I found this package’s neighbour, go/scanner, which was exactly what I wanted. The scanner was able to read a byte slice one ‘token’ at a time, and tell me what special meaning it had in the Go language, if any. However, it didn’t require the code to actually compile, which was exactly the simplicity I was looking for.

I had a bit of extra time during the day that I spent on reading up on Go templates. I’ve known about them for a while, but I’ve never actually used them before. I have 0 doubt this is still obvious from reading the template code…

Day 3: Templates

OK the title lies, I spent about half of the time getting the templates to work, and fixing bugs in the parser when I realised that I needed more information than what I previously thought. The rest was spent hooking together the parser, and creating a runnable binary. This day was also the day where I had to decide if I wanted to present what I had made internally to the company. I went for ‘yes’, not at all knowing what that actually would entail.

Day 4: Make Things Presentable

At the start of the day I already had a working prototype. There were a couple of bugs still around (e.g. ... for varargs didn’t quite work), but those were squashed relatively quickly. Now I just had to make it so that people could quickly learn how to use it, and want to use it. This meant creating an amazing README. I’m quite happy with how it all turned out.

I paid a designer on Fiverr to create a simple logo for the project, and I got what I paid for. You’re free to interpret that how you will, but I’m not complaining.

In order to really showcase the simplicity of the tool, I went an created an asciinema recording of how I would use it my day-to-day work. Not gonna lie, I did a lot of takes before I settled on a recording where I didn’t make that many typos (only 6). I sped up the recording 2 times to not make it boring to watch.

Side note, it turns out you cannot embed a video recording in a README, but you can embed a GIF. Asciinema creates these really cool hybrid video/text files (you can copy/paste text from these hybrids), but I would rather have something that catches the eye in the README and quickly showcases Mokku. So I had to install a couple of other tools to turn the recording I had stored locally into a GIF.

The rest of the day was spent putting together slides for the presentation I was making to the company the next day.

Day 5: Presentation

I know very little about presenting work like this, but what little I do know I used. Namely start with why and putting only a couple of words on each slide, but having many slides.

I made the repository public, did some final bit of clean up, and spent most of the rest of the day watching other presenters and preparing for my own presentation. Since we were all working remotely (if you’re reading from the future: this happened back when the entire world was in quarantine) it’s really hard to tell how well the presentation went. Honestly, I don’t even know if my slides were showing — I just jumped into it hoping for the best. No regrets!

Conclusion

I’m pretty happy with how it all went. I ended up with a good implementation that not only works but it’s also something I’d be happy to iterate further on. I do have some remaining work that needs to be done before I’m happy releasing a version 1 of Mokku. If you’re new to Go or open source, there are several issues that you could help with if you wish.


Roger Guldbrandsen

Written by Roger Guldbrandsen.