Categories: Web Dev Training

One Easy Way To Speed up your Rails Tests and RSpec

There comes a time in the life of every Ruby on Rails project where you and your team will end up with long running tests. Rails tests can contain factories, fixtures and lots of setup procedures before tests are executed, and all of these can contribute to major slowness in the test runs.

I’ve seen four ways of dealing with slow running tests in Rails:

  1. start deleting tests (or mark them as skip-able): the drawback is your test coverage drops and you may end up with more bugs
  2. use more integration tests rather than unit tests: this exercises a lot of code paths so test coverage won’t drop too much but in the end most developers will write integration tests that exercise the “happy path”
  3. Run your tests in parallel
  4. Run only the tests that were most likely to be affected by recent code changes

The latter two methods are much better than the first two.

My favourite so far is #3 because it still runs all of the integration and unit tests that you have but makes use of the fact that you can offload the work of running tests to multiple machines. Everyone now has access to multiple machines through AWS (Amazon Web Services) or Microsoft Azure or RedHat’s cloud. You can even run tests in parallel on your local development machine.

Run Your Ruby on Rails Tests In Parallel

The idea is that each test file will be run in separate processes.

If you have 5 tests that have a duration 2 minutes, in sequential runs it will take 10 minutes to run the whole test suite. If you have 5 processes available for parallel runs, it will only take 2 minutes to run the whole test suite.

That’s a huge difference and means you can make 30 test runs in an hour rather than 6 test runs.

Splitting RSpec test files into multiple files

However, some of your Rails tests may take longer; within the spec you could have multiple test cases and contexts that are taking too long. For example, one test context with a few tests could be taking 1 minute while the rest of the test cases in that file only take 10 seconds. At that point, you can split the long-running test context into multiple files.

Here’s an example of how that might look like:

# spec/my_controller_spec.rb
describe MyController do
  context 'Slow tests' do
    it 'runs slowly #1' do
      # ...
    end
    it 'runs slowly #2' do
      # ...
    end
  end

  context 'Faster part of the test suite' do
    it 'runs in 10 seconds or less' do
      # ...
    end
  end
end

And now here’s how we could split that controller rspec test file into multiple files.

# spec/my_controller_spec.rb
describe MyController do
  context 'Faster part of the test suite' do
    it 'runs in 10 seconds or less' do
      # ...
    end
  end
end

# spec/my_controller_slow_1_spec.rb
describe :MyControllerSlow1 do
  def self.described_class
    MyController
  end

  include_context 'my controller helpers'

  it 'runs slowly #1' do
    # ...
  end
end

# spec/my_controller_slow_2_spec.rb
describe :MyControllerSlow2 do
  def self.described_class
    MyController
  end

  include_context 'my controller helpers'

  it 'runs slowly #2' do
    # ...
  end
end

The reason this works is because we override the class method described_class. This method is used by the rspec-rails extensions that make it easier to test Rails classes with RSpec.

By using shared contexts and helpers and by splitting files, you can optimize your Rails tests even further.

(If you liked this article, I have written about using mocks with Django and Python unit and integration tests and using Protractor with AngularJS and how you can take screenshots with Selenium during test runs.)

Categories: Software Development

Automating Simple Tasks with Scheme (Competing with Perl, Python and Ruby)

Racket/PLT Scheme Logo

reddit user by the name of alanshutko stated what was necessary to make Scheme, Common Lisp, Haskell, and other non-mainstream languages more appealing to the average programmer.

Compare that with the types of simple programs we see in Perl and Python. “I have a bunch of files, and I want to rename them all according to some pattern.” Common problem, easy solution. “I’ve got a log file full of email addresses, I need to strip them out from the log entries, remove duplicates, and add them to a database.” Again, fairly simple, fairly small, really useful. When Haskell can compete on those types of problems, it’ll be easier to induce people to learn it. (Same with CL, my fav language….)

So here is a Scheme program that does this. It is written to use MzScheme because that’s the only Scheme I have installed in Windows at the moment. Thus, it takes advantage of PLaneT and the other libraries that come with MzScheme.

Hopefully this can convince others that Scheme is a good language for common tasks.
Continue reading “Automating Simple Tasks with Scheme (Competing with Perl, Python and Ruby)”