The Power of One Test

A developer experience and quality control measure I take on programs I’m building, even small ones, is always to write at least one test. Here’s an example, from this blog: // cypress/e2e/index.cy.js it('shows the homepage', () => { cy.visit('/'); cy.get('article').should('have.length', 10); }); The test loads the homepage and confirms ten articles. The test framework, Cypress, is inconsequential– the point is the test. Should we write tests? What kind, and how many? It’s easy to overthink it; don’t. The difference between zero tests and one is massive. ...

August 20, 2026

Writing the DOM with fs

How can I output the entire DOM to a file in a JavaScript test? Testing Library is amazing. But, one area I struggle with it: when writing high-level integration tests, when an assertion fails, the output can be noisy and incomplete. It makes debugging tough. The test runner says something like: “I couldn’t find ‘Submit’ in these two thousand lines of HTML, which are so big I’ve truncated for you.” ...

January 30, 2026

Custom Ipsum for Real-World Testing

Pastures which are subject to overflow should be avoided. All lambs born in April or May should be drenched about August or September following, to be certain of ridding them of worms that may later cause their death. This is output from a tool I built called Veterinary Ipsum. It’s something I’ve created a few times: a Lorem Ipsum generator specific to my company’s business domain. What is Lorem Ipsum? Lorem Ipsum is placeholder text used to communicate the design of a document. If you’ve ever seen website copy like “Lorem ipsum dolor sit amet”, that’s Lorem Ipsum. ...

June 27, 2025

Thinking of Bugs in Classes

We spent the time writing tests, and yet, a bug survived. Should we just stop writing tests? No, but we should maybe write better tests, and think about them differently. In this post, I’d like to explain a mental model I have that helps me write and maintain tests: thinking of bugs, and the tests that cover them, in classes. Bugs and Tests in Classes Every test has limitations. Unit tests miss the big picture, end-to-end (E2E) tests miss the details. Rather than chasing the impossible, that the test suite catches all bugs, I’ve found it’s preferable to think about bugs and tests in classes, like the classifications of the animal kingdom. ...

September 3, 2023

Making Sense of Code Coverage

Code coverage, the percentage of your code covered by automated tests, is a metric associated with code quality. In this post, I’d like to explore the limits of this idea. The higher-coverage-is-better metric I’m discussing could be summarized as: Coverage percentage up: good job! Coverage percentage down: let’s fix write more tests to raise the percentage. This perspective is not a Straw Man argument; it’s real! And here are the challenges I’d offer: ...

March 28, 2023

The Factory Pattern, Explained in Ruby

In this post, I’ll explain what factories are and why you want them, using Ruby. The FactoryBot gem is ubiquitous in Ruby and Ruby on Rails testing. If you aren’t familiar with it, you might be wondering, what’s the point? Wouldn’t it be simpler to build objects myself? An Example Let’s say we’re unit testing a full_name method on a User class. full_name takes two pieces of data, first_name and last_name, and combines them with a space. Let’s also assume that we’ve tried to ensure data integrity by requiring the presence of these two fields. ...

October 17, 2022

RSpec.describe vs. describe: Which Should I Use?

Ruby’s RSpec describe block has two common syntaxes. Which should you use? # With `RSpec` module name RSpec.describe TestedClass do end # Without module name describe TestedClass do end Disclaimer: they both work. But I’m assuming since you’re here, you’re curious about the distinction, or want to make a reasoned choice. TL;DR: I suggest using the RSpec module name. The Options The global availability of describe is called the Global Namespace DSL. RSpec made describe available on Object, the default root of all Ruby objects. The intent was to let us write specs without explicitly specifying the RSpec module. ...

April 2, 2022

On Disabling Tests

Today I want to talk about a common technique: disabling failing tests to allow a feature to ship. Maybe sometimes you gotta do it. But long-term I think it causes more problems than it solves. Here’s the scenario: we’re shipping an important hotfix, but there’s one red test blocking a green suite, and thus our deploy. This test is flaky– it’s known to pass and fail on the same commit. Folks on our team are suggesting disabling it. Wanting to be a team player, we disable the test with a short commit, “Disable this test for now” and ship our code. ...

February 22, 2022

Want Better Automated Tests? Hard-Code Your Expectations

Hard-coded test expectations have many benefits that I’ll explore in this post. Here’s a kind of assertion I see often in tests: # Code class User < ApplicationRecord def full_name "#{first_name} #{last_name}" end end # Assertion expect(user.full_name).to \ eq("#{user.first_name} #{user.last_name}") And here’s that same assertion with a hard-coded expectation, which is almost always better: expect(user.full_name).to eq("Jake Worth") A hard-coded expectation is an assertion about behavior that is just dumbly spelled out. They’re better because: ...

January 25, 2022

ExtractRSpecLet

Today I got to see the :ExtractRspecLet command from the vim-weefactor plugin. It does what the names suggests, converting this: # spec/model/foobar_spec.rb foo = FactoryGirl.create :foobar To this: # spec/model/foobar_spec.rb let(:foo) { FactoryGirl.create :foobar } It also moved the new let from inside my it block to right underneath my context block. Awesome! h/t Josh Davey and Dillon Hafer

April 21, 2021