Skip to content

Rodrigo Urubatan – About Code

Helping ruby developers to use the best tools for each job so they can solve hard problems, with less bugs and have more free time.

Menu
  • Home
  • My last presentations
  • About
  • Privacy Policy
Menu

How to improve Rails testing speed using Git

Posted on 2018-02-23 by Rodrigo Urubatan

I did a presentation in 2018 RubyHACK and will do the same presentation in 2018 TheConf called “Put Git to work: increase the quality of your project, and let git do the boring work for you”, one of the subjects in the presentation is how to use git to run tests only for the changed files before you push anything to the shared git server, and the code is really simple as you can see bellow:

The main idea is before pushing anything, check what files were changed in your branch compared to the same branch on the server, then run the tests for that files.

The code bellow is not perfect, it assumes the following:

  • Every file under the app directory has an equivalent in the test directory ended in _test.rb
  • if there is a configuration file changed, all tests will be executed
  • If there is one test file missing (corresponding to one of the changed files), the push is aborted
  • if the tests fail, the push is aborted

Of course, these assumptions are not perfect, there is one “hidden” assumption there, that you have an integration test that will run all tests for every push, but the idea here is to streamline the process and prevent tests not being executed “just because they take a long time”

But lets check the code now:

#!/usr/bin/env ruby
branch_name=`git symbolic-ref -q HEAD`
branch_name = branch_name.gsub('refs/heads/', '').strip
changed_files = `git diff --name-only #{ARGV[0]}/#{branch_name}`.split("\n").map(&:strip).select{|n| n =~ /\.rb$/}
#run the file specific test
test_files = changed_files.map do |name|
  if name =~ /^app/
    name.gsub('app/', 'test/').gsub(/\.rb$/, '_test.rb')
  elsif name =~ /^test/
    name
  else
    nil
  end
end.reject(&:nil?).uniq
#abort if there is a test missing
unless test_files.reject{ |n| File.exist?(n) }.empty?
  puts %Q{
      Aborting push because there are missing test files: #{test_files.reject{ |n| File.exist?(n) }}
  }
  exit 1
end
#if there are config files changes, run all tests
unless changed_files.select{ |n| n =~ /^config/ }.empty?
  test_files = ''
end
system('git stash')
result = system("rails test #{test_files.join(' ')}")
system('git stash apply')
unless result
  puts %Q{
    Aborting push due to failed tests
  }
  exit 1
end

the code above should be saved in a .git/hooks/pre-push file for your project, and remember to make that file executable so that it will run before every push automatically.

Of course the test assumptions can be changed to match your project, and a better heuristics to define what tests affect each file would be great, but to have a really good guess we would need a code a lot more complex, and this is already good enough for simpler cases.

This code is the sample from the presentation, the version I’m currently using assumes also the following:

  • If there is a controller, view, css or javascript file changed all cucumber tests must be executed
  • Gemfile* yarn.lock and package-files.json have the same “run all tests” effect that any configuration file
  • The tests are written with rspec, so the test file name changed to directory specs with the extension _spec.rb

Do you like the idea of git taking care of running your tests for you? What do you think of the assumptions used in the script?

please leave your opinion in the comments bellow.

Related

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Recent posts

  • Why Embrace Nesting in Ruby Modules?
  • An easy way to have a local “Github Copilot” for free
  • SPA without touching Javascript – The magic of Ruby on rails and Hotwire
  • I see Dead Jobs everywhere (sidekiq DeadSet)
  • Quick tips that help: rails notes

Arquives

  • May 2024
  • April 2024
  • February 2023
  • January 2023
  • December 2022
  • June 2021
  • March 2020
  • January 2020
  • July 2019
  • June 2019
  • May 2019
  • October 2018
  • September 2018
  • August 2018
  • July 2018
  • June 2018
  • May 2018
  • February 2018
  • January 2018
  • November 2017
  • August 2015
  • August 2014
  • July 2014
  • August 2007

Categories

  • AI
  • articles
  • cfp
  • firebase
  • gems
  • git
  • opinion
  • presentations
  • projects
  • rails6
  • ruby
  • Sem categoria
  • server-api
  • tutorials
  • Uncategorized
© 2025 Rodrigo Urubatan – About Code | Powered by Minimalist Blog WordPress Theme