Unit tests: what we're actually arguing about

Four voices argue about unit tests. The debate dissolves once you separate coverage-as-target from coverage-as-detector, with testability as the real prize.

July 24, 2026 · 13 min · Omar Crosby

The pair-programming session that made me write tests first

Years ago, on my first day at a new company, I sat down for what I thought was going to be a normal pair-programming session. There was a story on the board — I no longer remember what it was, exactly. Some feature, a handful of requirements, the usual shape of a first ticket at a new job. I read the requirements, my mind raced ahead to how I’d build it, and I started talking through my approach. ...

July 18, 2026 · 8 min · Omar Crosby

Testing Go with Ginkgo and Gomega without giving up go test

If you’ve never looked at Ginkgo and Gomega, there’s a decent chance you’re picturing something that replaces go test — a separate test runner, a separate CI step, another tool your team has to adopt wholesale before anyone sees a benefit. That picture is wrong, and it’s worth correcting up front, because it’s the single biggest reason Go developers who’d genuinely enjoy Ginkgo never try it. Here’s the fact that should change your mind: a Ginkgo spec is a Go test. It compiles into the same test binary, it runs when you type go test ./..., and your existing CI pipeline doesn’t need to know Ginkgo exists. What Ginkgo adds is a richer vocabulary for organizing specs — nested Describe/Context/It blocks instead of a flat list of Test* functions — plus first-class suite lifecycle (BeforeSuite/AfterSuite), table-driven specs, async timeouts, and labels for slicing a suite into subsets. Gomega adds the assertion language (Expect(x).To(Equal(y))) that makes failures read like a sentence instead of a %v != %v diff. ...

July 9, 2026 · 12 min · Omar Crosby

How writing tests first changes the shape of Go code

Most of the debate around test-first development gets stuck on process — red-green-refactor, coverage percentages, whether it slows you down on day one. That debate misses a simpler, more concrete effect, and you don’t need to know Go, or even know how to code, to follow it: Whichever thing you write second has to bend to fit whatever you wrote first. Write the code first and the test second, and the test has no choice but to accommodate whatever the code already does — however it talks to the database, however it calls the network, however it happens to be built. Write the test first, and it’s the code’s turn to bend: it has to be built in whatever shape lets the test — which doesn’t have a real database or a real network sitting around — actually run. That’s the entire mechanism. Nothing about willpower, experience, or caring more. Just: which one existed first gets to set the terms. ...

July 9, 2026 · 13 min · Omar Crosby

neospec: a self-contained test runner and coverage tool for Neovim plugins

One Go binary that manages its own Neovim, runs Lua tests inside the real editor, and emits LCOV/Cobertura/JUnit — no system install, no vendored framework, no shell-script gymnastics.

July 5, 2026 · 6 min · Omar Crosby