def unlock_next
curriculum
.unlocked_for(student)
.reject(&:completed?)
end The problem
Red-green-refactor only works when the loop is fast. Once the suite takes minutes, you start running one spec file by hand and hoping it’s the right one. You miss the integration spec three directories away that also goes through the method you just changed, and find out in CI.
File names and requires don’t tell you which examples reach a method. Only running them does.
The fix
You change Enrollment#unlock_next. In your editor, a code lens above the method:
# ▶ reached by 4 examples · run them
def unlock_next
curriculum.unlocked_for(student).reject(&:completed?)
end
On the command line:
$ ra specs_that_reach Enrollment#unlock_next
spec/models/enrollment_spec.rb:8
spec/models/enrollment_spec.rb:21
spec/requests/progress_spec.rb:44
spec/system/student_dashboard_spec.rb:12
It’s rspec-shaped, so it pipes straight in:
$ rspec $(ra specs_that_reach --since HEAD)
4 examples, 0 failures · 0.8s
--since takes the methods changed in a diff, so the agent, your editor and a pre-push hook can all
ask “which examples does this change touch?”
How it works
Every call tree in the recording is stamped with the spec example that produced it. That gives a map
from each example to every method it reached, and specs_that_reach reads it backwards: from a method
to every example that reached it, directly or through any depth of calls.
It lists examples, not files, because a file with forty examples might only have two that reach your method.
Limits
- As fresh as the last recording. A spec written since the last recorded run isn’t in the map yet. Run it once and it is.
- A brand-new method has no examples. On the first red that’s expected: the spec you’re writing is the one that will reach it.
- Code isn’t the only input. A change to configuration, a YAML file or a migration can change behaviour without touching a method. Run the full suite for those.
Related tools
testing_pyramid
The boundaries your pyramid misses. Seams that are only ever crossed through a double, never for real, mapped onto your testing pyramid. Record production too and they're ranked by traffic.
See more →dead_api
Find dead public API. Public methods no caller reached in any recorded run, including the ones whose only caller is their own spec. Greyed out in your editor.
See more →split_interface
Split a fat interface. A class whose callers each use a different slice of it. It names the role interfaces to split it into, measured from who actually calls what.
See more →