Introducing Test Budget: a linter for test performance

Ask questions Research chat →

https://thoughtbot.com/blog/introducing-test-budget · scraped

ruby testing

Attachments

Scraped Content

— 641 words · 2026-05-19 19:25:54 UTC ·

Excerpt

![](https://prod-files-secure.s3.us-west-2.amazonaws.com/871f1661-80b8-4d0c-ac3b-2adfc6ff4c66/f5bc3899-5ebf-46e5-add6-8769a020947f/aEccJrh8WN-LV5_m_default-article-background.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=ASIAZI2LB466VXQQEKYV%2F20260519%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20260519T192553Z&X-Amz-Expires=3600&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEBMaCXVzLXdlc3QtMiJHMEUCIQD8DbU9ddwSjuSCO1z769e1LpnaJoyp2rTAY%2F45N39aegIgQ86Ev2OsMXNteYfkw4RJHLmdOWYY8lOEMpp7FXjemk8qiAQI3P%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FARAAGgw2Mzc0MjMxODM4MDUiDJMLL9mELFwmcCO5lSrcA%2BusRt9W%2FnecRJUGnDwXGUbkPcRVN%2BaWAQh8js7YPfxG%2FSWqgmdNA5DG6gkIGz5B5hLNhRVO7txX%2BZWluRYbVmBNvYPOev61aL5ONhTQ8Yd69NYEwE5qwu%2FVeBClViyyInZoZeIj7OaVyy8%2FVpAOjgnHePlsK7SxTKlmXYmds6guFbBVwYQ4QLMG8T%2FQnrxABm0PamlUvCzhoTTWP6e22pXSLgBN8y6C1g4iHFm6B3FJbefj4vj14o08zGNWlN9gPQM7Iw94QEvsi6%2F3pSdCB3OXTcLOkx%2BILH5pfS7l1YKavYNog1%2FdoDf%2FQhW5iQBlORgcBlOvJ6R6BpWGKFqA7F5OaMJ0IjFvxsyIsMuEEmp
![](https://prod-files-secure.s3.us-west-2.amazonaws.com/871f1661-80b8-4d0c-ac3b-2adfc6ff4c66/f5bc3899-5ebf-46e5-add6-8769a020947f/aEccJrh8WN-LV5_m_default-article-background.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=ASIAZI2LB466VXQQEKYV%2F20260519%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20260519T192553Z&X-Amz-Expires=3600&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEBMaCXVzLXdlc3QtMiJHMEUCIQD8DbU9ddwSjuSCO1z769e1LpnaJoyp2rTAY%2F45N39aegIgQ86Ev2OsMXNteYfkw4RJHLmdOWYY8lOEMpp7FXjemk8qiAQI3P%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FARAAGgw2Mzc0MjMxODM4MDUiDJMLL9mELFwmcCO5lSrcA%2BusRt9W%2FnecRJUGnDwXGUbkPcRVN%2BaWAQh8js7YPfxG%2FSWqgmdNA5DG6gkIGz5B5hLNhRVO7txX%2BZWluRYbVmBNvYPOev61aL5ONhTQ8Yd69NYEwE5qwu%2FVeBClViyyInZoZeIj7OaVyy8%2FVpAOjgnHePlsK7SxTKlmXYmds6guFbBVwYQ4QLMG8T%2FQnrxABm0PamlUvCzhoTTWP6e22pXSLgBN8y6C1g4iHFm6B3FJbefj4vj14o08zGNWlN9gPQM7Iw94QEvsi6%2F3pSdCB3OXTcLOkx%2BILH5pfS7l1YKavYNog1%2FdoDf%2FQhW5iQBlORgcBlOvJ6R6BpWGKFqA7F5OaMJ0IjFvxsyIsMuEEmpa0VUOxSI0GTXKu%2B60%2BpSqvIj8HoyQbjFwVyON8ZHoQb1BUU4K3vZAPJobNYzILCMB6i9NQZjDbAsH2r2s6c%2BXl8HBn5CKc0LAjrsmIqIZKGD5fftEFWs4P0SM%2BGp0%2B%2FtliwqDvVEqlD6lfg9azU2C3HTzNEDVtypOkc0NcqZNAEz1HTSOzWHw356xluNTxRRj0Zgyir1oj3ksBRawinPmFW1qcGDvksybFx24VpUsU%2F%2BkviZcRNlAwSMvSaWEmuo%2BCh93vgI9y79ezroTMM%2FastAGOqUBGJGIVHXxc%2FxYZjT7k26i6a3Nn7mMnzJ35wcQbb%2F0mxlIVxezVQ2o2QjUvF%2FzXVZp2eTy0CeC8M%2FdpjMR0nOq4OqgVx8NmRdZC2ZV7LyCrN4aoh4bdoLKOdnOcEyqskpDmElqD0L2gpRNxUvv%2B8nVARiC%2BzeZGNYvWCu56IEyrfZ3C7aJzbGY1EDfw6Zq9pwmMTIa2VVdiep%2BSNWbd8jiUtzVYqW5&X-Amz-Signature=48a6050777689fedddfd26297c789d13c1eeeff420bd05d676a89c7e1d336cf3&X-Amz-SignedHeaders=host&x-amz-checksum-mode=ENABLED&x-id=GetObject) No one sets out to write a slow test, and yet it happens. A test matcher that burns through a full Capybara timeout. An innocent-looking factory that cascades into dozens of records. One test at a time, your suite gets slower. By the time you notice, CI takes hours and nobody wants to touch it. Having tests is not enough. We need fast tests. If tests are slow, developers won’t run them locally. When only CI runs the full suite, feedback loops stretch from seconds to hours. Without visibility, performance will always be an afterthought. We have no shortage of performance monitoring tools for production, but very few for tests. I built Test Budget to fill that gap. It reads your test run timings and reports when they exceed a configured budget. It doesn’t change how your tests run. It just tells you when they’re too slow (before it gets worse). You can set budgets at two levels: - Suite-level: your entire test suite should run in under 10 minutes, for example. - Per-test-type: model tests should run in under 1.5 seconds, system tests under 10 seconds, and so on. You don’t have to pick numbers from thin air. Test Budget can generate a starter config from your existing test results. First, run your tests with RSpec’s JSON formatter to produce a timings file: ```plain text bundle exec rspec --format json --out tmp/test_timings.json ``` Then generate a starter config from those results: ```plain text bundle exec test_budget init tmp/test_timings.json ``` It derives budgets from your actual data: - The total suite budget is set 10% above your current total, giving you headroom to keep adding tests without immediately blowing the budget. - The per-test-type budgets are based on the 99th percentile. Your slowest 1% of tests are the ones you need to fix. The rest already pass. These are starting points. The generated config is a plain YAML file you can tune to match your team’s standards. Then run the audit after your tests: ```plain text bundle exec test_budget audit Test budget: 1 violation(s) found 1) spec/system/signup_spec.rb -- creates account (11.20s) exceeds system limit (6.00s) ``` The audit tells you exactly which tests to look at. From there, you can make them faster. The README has a list of strategies to use in these cases. Like RuboCop’s generated todo, Test Budget has an allowlist. Instead of bumping the budget to accommodate a slow test, you allowlist it with a reason. This keeps the budget honest for everything else and makes it clear which tests need attention. ```plain text allowlist: - test_case: "spec/services/invoice_pdf_spec.rb -- generates PDF with line items" reason: "PDF generation is inherently slow, tracked in #1234" expires_on: "2026-04-01" ``` Allowlist entries have an expiration date. When they expire, the test starts failing the audit again. This creates friction on purpose. It keeps entries from quietly overstaying their welcome and encourages you to fix the underlying issue instead of sweeping it under the rug. The right budget depends on your team and project, but I’d encourage you to be aggressive. Way too many teams are comfortable with 10+ minute test suites. That is an awful lot of time to wait for feedback. Fast tests are one of the best things you can do for developer productivity. The goal isn’t zero violations on day one. It’s to stop overspending and make test performance visible. Start with what you have, then work on improving it. Give Test Budget a try: ```plain text bundle add test_budget bundle exec rspec --format json --out tmp/test_timings.json bundle exec test_budget init tmp/test_timings.json bundle exec test_budget audit ``` ## About thoughtbot We've been helping engineering teams deliver exceptional products for over 20 years. Our designers, developers, and product managers work closely with teams to solve your toughest software challenges through collaborative design and development. Learn more about us.

Visibility

Visible to everyone

Reading Status

Related Bookmarks

My Note


Saved!

Annotations

Export as Markdown
+ Annotate selection

Add Annotation