Ctrlspecs
What's the responsibility of a controller?
Render. Redirect. Flash.
I'd argue that those are, in fact, the only responsibilities controllers have. Now, I realize controllers' actions are often burdened with resource creation, deletion and updating, but let's keep it real here - all this logic belongs to another object, usually a service. And indeed, most of the non-trivial, well designed applications use service objects, instead of cramming everything inside poor controllers.
Installation
Add this line to your application's Gemfile:
gem 'ctrlspecs'
And then execute:
$ bundle
Or install it yourself as:
$ gem install ctrlspecs
In your rails_helper.rb add:
RSpec.configure do |config|
config.extend Ctrlspecs
...
end
Usage
Ctrlspecs gives you a few helpers, which are basically just shared examples testing what your typical controller does:
- what template does it render
- where does it redirect to
- what message does it flash
- what service does it call
subject { post :create, params } # subject is required
it_renders_template :create
it_redirects_to 'resources_path(assigns(:resource))' # the path argument will be evaled
it_flashes notice: I18n.t('shared.created')
it_calls_service SuchService
Ctrlspecs also provides contexts for testing failures:
mock_save_record_failure
mock_service_returning_error, VeryService, Response::Error
So, how does your typical controller action spec look like now?
require 'rails_helper'
describe PostsController do
describe 'POST #create' do
let!(:params) do
{ post: { content: 'such content, wow' } }
end
subject { post :create, params }
context 'success' do
it_redirects_to 'post_path(assigns(:post))'
it_flashes notice: I18n.t('shared.created', resource: 'Post')
end
context 'failure' do
mock_save_record_failure
it_renders_template :new
end
end
describe 'GET #index' do
subject { get :index }
it_calls_service Posts::GetAllTheFrigginPosts
end
end
Contributing
- Fork it ( https://github.com/mwsteb/ctrlspecs/fork )
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create a new Pull Request