Testing ActiveSupport concern modules

Using modules to share code between classes in Ruby is a commonly used method to add re-usable behaviour without blocking the inheritance chain, the Rails ActiveSupport::Concern adds some convenience methods to do so. What (at least in my opinion) should not be forgotten is to test the usage of such modules on your classes, this can actually be achieved fairly easily creating a module with test code that you can then again include in your tests.

Take this very contrived example module which adds an instance method to the classes it is included in:

module ReverseName  
  def reversed_name 
    name.reverse    
  end               
end                 

It’s function could be tested with the following test:

test 'reverse name' do                             
  assert_equal 'htimS nhoJ', @name_reversable.reversed_name 
end                                                

This can be poured into a module using ActiveSupport::Concern that can be included in test cases of other classes like so:

module Concerns                                          
  module ReverseNameTest                                 
    include ActiveSupport::Concern                       
                                                         
    included do                                          
      test 'reverse name' do                             
        assert_equal 'htimS nhoJ', @name_reversable.reversed_name 
      end                                                
    end                                                  
  end                                                    
end                                                      

In Rails projects I usually put shared test code inside the directory test/test_helpers, to have these loaded when running tests you will have to add the following line to your test_helper.rb:

Dir[Rails.root.join('test/test_helpers/**/*.rb')].sort
                                                 .each { |file| require file }

To now use this test module on a class that can make use of it we can include the test module in that model’s test like so:

require 'test_helper'                                             
                                                                  
class ContactTest < ActiveSupport::TestCase                       
  include Concerns::ReverseNameTest                               
                                                                  
  setup do                                                        
    @name_reversable = Contact.new(first_name: 'John', last_name: 'Smith') 
  end                                                             
                                                                  
  test 'name' do                                                  
    contact = Contact.new(first_name: 'John', last_name: 'Smith') 
    assert_equal 'John Smith', contact.name                       
  end                                                             
end                                                               

If you want to verify that the test gets executed for your model you can purposely break the test(s) to see them fail like shown below: