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: