|By Manuel Weiss||
|October 11, 2013 12:00 PM EDT||
Developers need to be able to run tests quickly or they will stop running them.
Slow test suites are often partially caused by slow startup times. Once you've eliminated this problem, you might want to take a look at individual tests.
Note that test suites stress your code in a totally different way from the production environment. A slow test suite doesn't mean your app will be slow in production and the other way around. Never optimize your code for the test suite.
Sometimes slow tests are an indication of slow code, always measure to be sure.
Always start by measuring the actual runtime of your test suite or individual tests when trying to speed them up. Always do a few test runs to get a feeling for the variance in time between test runs.
If your improvements are in the order of the runtime variance they might not be worth it.
We usually create a branch for our improvements in Git so we can easily compare to our mainline branch and abandon a bad idea.
Inserts might be slow
On Ruby 1.8.7 inserting records through ActiveRecord was really slow. Especially in loops, repeatedly called setup methods, or factories. In Rails 4.0 with Ruby 2.0 this has gotten less of an issue.
Unnecessary round-tripping to the database server and models with lots of callbacks, uniqueness checks, and other slow code can still slow down your test suite. A lot of methods and validations on a model can be tested without saving it.
Avoid connecting to remote services
You don't want your tests posting video to YouTube or sending email over SMTP.
The easiest way to test if you're connecting to external services from your test suite is to temporarily turn off your network.
We usually stub out external services with a mock implementation. Alternatively you might want to use Webmock or override
Net::HTTP#start for a more general solution.
Avoid connecting to local services
Connecting to local services can slow down your test suite as well, but in some cases it's pragmatic to do so. Connecting to a local database seems alright, but requiring memcached might not be necessary. It's up to you to make the call (pun intended).
Some people go so far as to implement their business logic in separate modules which are then included in their models. This allows them to run tests without booting Rails. As a general rule I don't like to change my code just to speed up tests.