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:
- Setup parallel_tests just like in the Readme, but stop at step 4.
- Load the parallel_test rake file into your plugin (below)
- 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