Matthew Lindfield Seager

Matthew Lindfield Seager

Automating Minitest in Rails 6

I’m building a new app in Rails 6 (6.0.0.rc1) and while I use RSpec at work I’ve been enjoying using Minitest in my hobby projects.

I’d love to know if there’s ways to improve my setup but here’s how I set up my app to run Minitest tests automatically with Guard (https://github.com/guard/guard)

Set Up

  1. Install the necessary gems in the :development group in ‘Gemfile’ and run bundle. While we’re at it lets give our minitest results a makeover with minitest-reporters:

    # Gemfile
    group :development do
      ...
      gem 'guard'
      gem 'guard-minitest'
    end
        
    group :test do
      ...
      gem 'minitest-reporters'
    end
    
  2. Finish the makeover by adding a few configuration tweaks into our test helper:

    # test/test_helper.rb
    require 'rails/test_help' # existing line...
    require 'minitest/reporters'
        
    Minitest::Reporters.use!(
      Minitest::Reporters::ProgressReporter.new(color: true),
        ENV,
        Minitest.backtrace_filter
    )
    
  3. Set up a Guardfile to watch certain files and folders. Originally I used bundle exec guard init minitest but I ended up deleting/rewriting most of the file:

    # Guardfile
    guard :minitest do
      # Run everything within 'test' if the test helper changes
      watch(%r{^test/test_helper\.rb$}) { 'test' }
        
      # Run everything within 'test/system' if ApplicationSystemTestCase changes
      watch(%r{^test/application_system_test_case\.rb$}) { 'test/system' }
    
      # Run the corresponding test anytime something within 'app' changes
      #   e.g. 'app/models/example.rb' => 'test/models/example_test.rb'
      watch(%r{^app/(.+)\.rb$}) { |m| "test/#{m[1]}_test.rb" }
    
      # Run a test any time it changes
      watch(%r{^test/.+_test\.rb$})
    
      # Run everything in or below 'test/controllers' everytime
      #   ApplicationController changes
      # watch(%r{^app/controllers/application_controller\.rb$}) do
      #   'test/controllers'
      # end
    
      # Run integration test every time a corresponding controller changes
      # watch(%r{^app/controllers/(.+)_controller\.rb$}) do |m|
      #   "test/integration/#{m[1]}_test.rb"
      # end
    
      # Run mailer tests when mailer views change
      # watch(%r{^app/views/(.+)_mailer/.+}) do |m|
      #   "test/mailers/#{m[1]}_mailer_test.rb"
      # end
    end
    
  4. Add relevant testing information to the README. I added the recommended approach (using bundle exec guard to automate the running of tests) but also included information on how to run tests individually or in groups.

  5. Commit all the changes to Git with a meaningful commit message (i.e. less what, more why)

Caveats

  • At the time of writing ‘guard-minitest’ (https://github.com/guard/guard-minitest) has not been updated for 18 months. It’s likely it’s complete and stable but it may not be getting the attention it deserves… even just a minor Rails 6 update to the template would be a good sign.
  • I’ve commented out the controller and integration tests in my Guardfile because I don’t have any of those (yet?). I’m still finding my way but I like the idea of testing all the bits and pieces in isolation and then just having a smallish number of System tests that exercise the major functionality.
  • The minitest-reporters gem and associated configuration are both optional. I just like a simple display with a splash of colour to easily see Red vs Green test states.