Fast Testing with Rails

So, I’ve been working on a project for my new workplace, and because of all the dependencies (which are all necessary - I checked), the test suite itself takes 6-7 seconds just to boot up.

My normal workflow on smaller projects is to have guard running, and then use TDD to drive the design of the application. This works pretty well, because on a smaller application, it only takes 1 second or so to run the test file.

However, when working with this current application - it’s taking 6-7 seconds between each save - which deters me from doing true TDD (I end up doing Test First Design instead - which isn’t the goal).

I’ve watched Gary Bernhardt’s videos at DOS, and this talk by Corey Haines, as well as the recent post on the thoughtbot blog, How We Test Rails Applications.

I realize that the issue of speed is because of including test_helper (or spec_helper), which include the Rails stack and the application’s dependencies.

So - all in all, I guess my question is:

What is the best way to create fast tests when needing to test classes that are dependent on Objects that inherit from ActiveRecord?

Ex:

  • Models with Associations
  • Service classes that use ActiveRecord Objects

Is that just the pain of testing Rails Models? Or should I be pulling out all business logic into Modules/Classes?

Those classes that are services, should I just be injecting the ActiveRecord object into the initialize function - so that I can send in a stub within the test?

Thanks!

We pretty much just use spring, and everything is fast enough for our TDD cycles to be non-painful.

1 Like

+1 on @benorenstein’s suggestion.

I’ve been using Spring as well, and it’s generally pretty simple to set up and run. I recommend adding a line to your spec_helper to reload spring whenever you edit a factory, as Spring won’t track factory changes automatically.

Having the test environment pre-loaded is 80% of the battle. The other two things to do if your test suite isn’t running fast that I would use the --profile option to find your slowest running specs. Sometimes one feature spec can be responsible for a huge portion of your suite’s slowness.

The other thing I try to do to keep suites fast is to access the database as little as possible. Don’t use create when build or new will do. Unless your test relies on associations, you should be able to avoid the DB in most cases.

With Spring in use, I think the effort to employ workarounds like having an ActiveRecord-less spec helper are overkill and of extremely limited marginal value.

Thanks, for the quick responses (both of you) !

Does this mean that, when using spring, you’d recommend not pulling business logic out of the Model Objects as well?

Definitely still extract logic out. Smaller classes are desirable not for speed, but for testability and solid design.

1 Like

Just to confirm, are these the steps?

  • Spring to get the 80% in.
  • Use build or build_stubbed as opposed to create
  • Extract stuff that can be removed from AR.

Yes, except:

See what @geoffharcourt said above.

I’ve added spring to the project, and things are much faster - thanks, @benorenstein !

One thing I’ve noticed with spring though (at least, in collaboration with guard), is that it’s finicky with some initializers (ex: an internal engine that is setting some defaults, redis and resque.

As such - there are some tests that are not intermittently failing that pass find when just running rake test:all.

Is there an easy fix for this that I’m missing?

You can add the initializers folder to the list of things that Spring watches (I do this with factories), and Spring will restart whenever you edit an initializer.

Thanks for the quick response @geoffharcourt!

The crazy thing - is that none of the initializers are being edited when this is happening. It just happens off the bat, and continues as I continue to run tests via guard.