I’ve been practicing Test-Driven Development (TDD) for years, and I’ve been using TDD in Go for as long as I’ve been using Go. So I was excited to see a book coming out about this very topic! I was so excited, in fact, that I invited author Adelina Simion to an interview over on the Cup o’ Go podcast, before I even had a chance to read it!
Now I have read it, and I’ve learned a few new things, and am ready to make my recommendation!
Publication Details
Test-Driven Development in Go 1st edition; by Adelina Simion, 342 pages. Published April 28, 2023 by Packt Publishing.
Prefer to watch this review?
Audience
“This book is aimed at developers and software testing professionals, who want to delivery high-quality and well-tested Go projects.” Preface, p. xii
I would add that anyone truly experienced with testing in Go will likely find Part 1: The Big Picture to be redundant. However, the later sections go over such a broad variety of topics, that virtually everyone is bound to find something new here, whether it be using godog for Cucumber-based integratoin/end-to-end tests, using Pact for contract tests, or picking up some new techniques for testing of concurrent code.
Prose Style
This book is written as a fairly direct, matter-of-fact, step-by-step guide. Through Parts 1 & 2, most chapters build on previous chapters, often using the same example project for illustration purposes.
Organization
This book is written in a progressive order. Chapters 1 and 2 are a basic overview of testing, with an obvious emphasis on testing in Go. These chapters define the main concepts and terms used throughout the book, and explain some of the benefits of Test-Driven Development (TDD).
Chapters 3 and 4 round out Part 1, and cover common third-party tools you may wish to use, such as mocking and assertion libraries, and introduce the reader to the concept of table-driven tests.
Part 2: Integration and End-to-End Testing with TDD naturally explains how to do Integration and End-to-End testing, but more important, at least in my opinion, it begins introducing some more advanced testing tools, such as ginkgo and godog, which are tools for more human-readable tests, as are commonly used in Behavior-driven development.
Part 2 is also where we find chapter 7, Refactoring in Go, which is so essential to both the why, and the how, of TDD, that it could easily fill multiple books. In fact, it has! (See: Refactoring by Martin Fowler and Working Effectivley with Legacy Code by Michael Feathers for some favorites.)
Part 3: Advanced Testing Techniques dives into some of the more specialized aspects of testing, with a discussion of testing concurrent code, the use of Go 1.18’s new Fuzz testing capabilities, and working with generics.
The progressive nature of this book does mean it’s a bit tricky to jump around. As one example, the section on refactoring illustrates the concept by refactoring code written in the previous sections of the book. This means that if you jump straight there, you may find the code samples to be a bit dense. However, even with this drawback, the textual descriptions mostly stand on their own. So if you do want to jump straight to the sections on Fuzz and Property-based testing, for example, you can still get the gist of the concept, even without following along with the code examples.
Content
This book touches on a ton of topics. Naturally, that means it can go only so deep on any of them. This is easily the biggest drawback of this book, in my opinion. The interesting topic of Fuzz testing, for example, gets just 4 pages.
You are not going to get enough information from this book to consider yourself an expert in assertion libraries, mocking libraries, dependency injection, property-based testing, or any of the many other topics covered.
However, if you are new to any of these concepts, this book will provide a gentle introduction, and get you up and running quickly. From there, of course, you can dig into other more in-depth materials on the specific topics you find most interesting.
I’d venture that very few developers or testers will, or even should, use all of the techniques in this book. But by reading this book, you’ll gain a high-level understanding of each of the included techniques, and when or if it makes sense for you to learn.
Here’s a quick rundown of the main topics covered:
- The Go
testing
package - Third-party assertion & mocking libraries
- Writing table-driven tests
- Behavior-driven tests with ginkgo and godog
- Contract testing with Pact
- Using tests to refactor safely
- Writing tests against a live database
- Fuzz & Property-based testing
- Testing concurrency
- Testing with generics
Accuracy & Omissions
I found only a couple of minor errors, on the order of an occasional typo or misused word. Nothing worth dwelling on.
There are a couple of minor things that seem to be missing, however. I’ll offer two examples:
On pages 54-56, we’re told about using deferred functions for test cleanup, but no mention is made of the t.Cleanup
function, which is preferred.
Also on page 58, as well as throughout other examples in the book, test helper functions are demonstrated, but they do not call t.Helper
, as they should.
What I Dislike
Go is an opinionated language, with some strong idioms and conventions. Some of the advice in this book goes against the established Go conventions. Whether that’s good or bad, of course, depends on whether or not you agree with the established conventions. I think it’s completely fair, even appropriate, to challenge established conventions, when there’s a reason. But I wish the book would have called these out, and made a case, rather than just making contradictory suggestions, which could leave some newcomers confused if they follow the book’s advice, then later learn that it’s unconventional.
Here are a few examples:
You should use assertion frameworks to compliment the simplicity of the
testing
package. (p. 85)
This contradicts the advice from the official Go wiki:
Avoid the use of ‘assert’ libraries to help your tests.
The case against using assert libraries is multi-faceted, and obviously not everyone agrees, but that is the official recommendation, so deserves a mention at the very least.
Likewise, the book recommends rather heavy use of mocking libraries, which is widely seen as sub-optimal in the Go community for a number of reasons. It also makes the common mistake of conflating mocks and stubs. This makes it a bit harder to separate the more controversial advice on mocking, from the less controversial advice on stubs-conflated-with-mocks.
So while the issues of assert and mocking libraries ultimately boil down to one’s opinion, I think it would be in order for a book like this to at least explain the official advice, and discuss pros and cons, rather than simply asserting (ooh, a pun!) the dissenting view as correct.
Physical Charactaristics
This book is physically what I’ve come to expect from any leading publisher. It’s mostly black and white, with curiously small number of color diagrams.
There are a number of diagriams and flow charts book, but the majority are black and white. Black and white is perfectly fine, in my opinion, so just makes me wonder why have any color diagrams at all. 🤷
Conclusion
This book covers a lot of important topics, which means you’re almost sure to learn something new and relevant for you. And that makes it worth the cover price, alone. However, the lack of depth means you’ll be reaching for additional resources to master the concepts this book introduces you to.
If you are a beginner in TDD or even more broadly, testing, in Go, this book will help you get on your feet.
If you consider yourself an expert in TDD or testing in Go, you’ll likely find some new insights here, as I did.
My only real complaint about the book is that it overlooks established Go conventions in a number of places, without offering an explanation. And this could lead some newcomers to the Go ecosystem to make suboptimal choices, or end up being confused.