Testing Rails Plugins on All Cores with parallel_tests

About 90% of my development is done on Redmine and well over half of that is done on Redmine plugins. That means that I write tests; a lot of tests. Over time though, they get slower and slower and start to become a drain on productivity (“5 minutes to run the tests on a feature that took 30 seconds?!?!”).

The limiting factor is that Rails runs tests sequentially, so it only takes advantage of a single CPU core. I’ve started to use a great tool called parallel_tests to use all four cores but it hasn’t been working on tests for Rails plugins’ due to how it loads.

Until now…

With a bit of hacking, I’ve figured out how to load parallel_tests inside my plugin’s test suite. The setup was actually really simple:

  1. Setup parallel_tests just like in the Readme, but stop at step 4.
  2. Load the parallel_test rake file into your plugin (below)
  3. Run the tests

Loading parallel_tests

Just pop this into your plugin’s Rakefile (assuming you installed the plugin version of parallel_tests)

1
2
3
4
5
parallel_tests = (File.join(File.dirname(__FILE__), '..', 'parallel_tests','lib','tasks','parallel_tests.rake'))
if File.exists? parallel_tests
  RAILS_ROOT = File.dirname(__FILE__)
  import parallel_tests
end

Using rake’s import statement, the parallel_tests.rake file gets loaded directly into the plugin’s Rakefile. This makes the rake parallel tasks available.

I also had to define RAILS_ROOT because I monkey around with it in my plugin. You may be able to remove it in your plugin.

Results

I set this up for my redmine_kanban plugin and it cut my test suite’s running time from 4 minutes down to 2 minutes 38 seconds, a savings of 1 minute 22 seconds. That’s a massive improvement when you start running the test suite 10, 20, or 50 times a day.

$ time rake
(in /home/edavis/dev/redmine/redmine-core/vendor/plugins/redmine_kanban)
/usr/bin/ruby1.8 -I"lib:test" "/usr/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader.rb" "test/unit/kanban_issue_test.rb" "test/unit/helpers/kanbans_helper_test.rb" "test/unit/issue_test.rb" "test/unit/sanity_test.rb" "test/unit/kanban_test.rb"
  * DEFERRED: #update_issue_attributes should return false if the issue didn't save.
Loaded suite /usr/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader
Started
...................................................................................
Finished in 63.503572 seconds.

83 tests, 267 assertions, 0 failures, 0 errors
/usr/bin/ruby1.8 -I"lib:test" "/usr/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader.rb" "test/functional/kanbans_controller_test.rb"
Loaded suite /usr/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader
Started
................................
Finished in 139.429962 seconds.

32 tests, 79 assertions, 0 failures, 0 errors
/usr/bin/ruby1.8 -I"lib:test" "/usr/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader.rb" "test/integration/kanban_board_test.rb"
Loaded suite /usr/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader
Started
..
Finished in 9.012205 seconds.

2 tests, 12 assertions, 0 failures, 0 errors

real    3m59.730s
user    3m32.413s
sys     0m21.733s
$ time rake parallel:test
(in /home/edavis/dev/redmine/redmine-core/vendor/plugins/redmine_kanban)
/home/edavis/dev/redmine/redmine-core/vendor/plugins/parallel_tests/lib/tasks/../parallel_tests.rb:4: warning: already initialized constant VERSION
4 processes for 7 tests, ~ 1 tests per process
Loaded suite -e
Started
.  * DEFERRED: #update_issue_attributes should return false if the issue didn't save.
Loaded suite -e
Started
.Loaded suite -e
Started
.Loaded suite -e
Started
.............................................
Finished in 14.261201 seconds.

31 tests, 56 assertions, 0 failures, 0 errors
...
Finished in 14.744914 seconds.

14 tests, 43 assertions, 0 failures, 0 errors
........................................
Finished in 52.973448 seconds.

41 tests, 180 assertions, 0 failures, 0 errors
...........................
Finished in 147.211034 seconds.

32 tests, 79 assertions, 0 failures, 0 errors

Results:
41 tests, 180 assertions, 0 failures, 0 errors
14 tests, 43 assertions, 0 failures, 0 errors
31 tests, 56 assertions, 0 failures, 0 errors
32 tests, 79 assertions, 0 failures, 0 errors

Took 156.279382 seconds

real    2m38.223s
user    0m1.600s
sys     0m0.416s

Don’t settle for Rails only using one core, put your quad core behemoth back to work.

Eric Davis

No related posts.

About Eric Davis

I founded Little Stream Software where I provide Redmine and ChiliProject services to help projects teams. I also created an ebook, Redmine Tips, were I show you how to become more productive using Redmine. I am also the author of Refactoring Redmine, where I go about refactoring Rails using Redmine as an example.

, , ,

Become more productive with Redmine     Get Redmine Tips »