How to Test Controller Concerns in Rails
Concerns are a new feature that was added in Rails 4. They allow to clean up the code in your models and controllers. They also allow you to share functionality between models or controllers. However, they can be a bit tricky to test in isolation. In this article, I want to show how you can test your controller concerns in isolation.
A Simple Scenario
We have a project that sells many different unique objects. Once someone purchases the item, we need to flag it as “out of stock”. However, we have several different controllers and different types of purchases that need this functionality. To reduce code duplication, we are going to put these in a concern.
module TransactionProcessing
extend ActiveSupport::Concern
included do
helper_method :process_sale
end
def process_sale(item)
item.is_in_stock = false
item.save!
end
end
If we want to test this concern, we need a controller to include it in. However, it would not be accurately unit testing to do this as there could be code in that controller that could affect the output of our test. Inside of our test, we can create a mock controller with no methods or logic of it’s own, and then write tests for that. If you are using RSpec, you can call methods directly using the subjectobject. Here is my example test using RSpec and FactoryGirl.
require 'spec_helper'
class FakesController < ApplicationController
include TransactionProcessing
end
describe FakesController do
it "should mark an item out of stock" do
item = create(:item, is_in_stock: true)
subject.process_sale(item)
expect(item.is_in_stock).to be false
end
end
And there you go! Easy, isolated tests for your controller concerns.