Recommendations for Faster Tests

Let's learn some performance tips to run tests faster.

We'll cover the following

Performance tips

The topic of Rails’ code structure and the attendant ability to write tests always winds up in a mixture of things everyone should try once, things we do regularly, things we wish we could do regularly, things we don’t do but generally regret not doing, and so on. In that spirit, here are a few recommendations:

  • Our current practice is moving complex transaction logic out of controllers into workflow objects, creating logic out of models and into factory or workflow objects, and (somewhat less often) view logic into presenters. All of those are plain non-Rails Ruby objects. David Heinemeier Hansson might say all of these lead to overly complicated code. That hasn’t been our experience. We should try it for ourselves.

  • We like to use SimpleDelegator to create a new object that has functionality that applies to an ActiveRecord object only some of the time, for example, logic about whether a user has access to a resource or logic for purchasing an item, which is needed only during the purchase process itself.

  • Where we can, we like to use immutable value objects, for instance, taking a start and end date from an object and making a DateRange class or taking a name class from a first name, last name, and so on. The value objects are super-fast to test and tend to attract logic.

  • In tests, we try to create as few objects as possible, touch the database as little as possible, and be aware of dependencies and places to mock that can limit the amount of setup a test needs.

  • RSpec has a —profile option that shows us the slowest tests in a test run. We need to be careful with it (often, the slow test will be the one that had the garbage collector run during it), but it’s a good thing to run now and then to try to speed up our slowest tests. The same configuration option that allows the use of --only-failures keeps a running list of every spec’s runtimes in the system. This can be useful to look at.

  • All that said, don’t despair if we can’t make this all work immediately. We’ve never quite been able to make an entire project work using the ActiveRecord-specific test helper. Our main problem is not making an individual test run, and it’s not keeping track of dependencies manually. Rather, the main problem has typically been integrating the separate sets of tests into the entire ecosystem of the project. That includes the ability to run the entire spec suite, other developers’ ability to run the suite, extra continuous-integration setup, and the like. Being aware of dependencies (and using Spring) provides most of the benefit with a fraction of the fuss. Still, it’s probably something we could be more aggressive about. Most of the codebases wind up with test suites that are slower than we’d like.

Get hands-on with 1200+ tech skills courses.