Controller tests - thuy-econsys/rails_app GitHub Wiki
Define FactoryBot User
Use FactoryBot's trait
to setup different users.
FactoryBot.define do
factory :user, class: User do
sequence(:email) { |n| "user-#{n}@example.com" }
password {"Password1"}
password_confirmation {"#{password}"}
account_type {:author}
trait :admin_user do
account_type {:admin}
end
trait :moderator_user do
account_type {:moderator}
end
factory :admin_user, traits: [:admin_user]
factory :moderator_user, traits: [:moderator_user]
end
end
Define helper methods
# /spec/support/controller_macros.rb
module ControllerMacros
def login_user
before(:each) do
@request.env["devise.mapping"] = Devise.mappings[:user]
sign_in create(:user)
end
end
def login_admin
before(:each) do
@request.env["devise.mapping"] = Devise.mappings[:admin_user]
sign_in create(:admin_user)
end
end
def login_moderator
before(:each) do
@request.env["devise.mapping"] = Devise.mappings[:moderator_user]
sign_in create(:moderator_user)
end
end
end
Include and require files
# /spec/rails_helper.rb
require 'spec_helper'
ENV['RAILS_ENV'] ||= 'test'
# ...
require 'rspec/rails'
# ...
require 'support/controller_macros'
RSpec.configure do |config|
# ...
config.include Devise::Test::ControllerHelpers, :type => :controller
config.include FactoryBot::Syntax::Methods
config.extend ControllerMacros, :type => :controller
end
Use the ControllerMacros methods to test code
# /spec/controllers/articles_controller_spec.rb
require 'rails_helper'
RSpec.describe ArticlesController, type: :controller do
let(:valid_attributes) {
{
:title => "Title",
:content => "Lorem ipsum..."
}
}
describe "GET index" do
context "when user logged in" do
login_user # ControllerMacros module method
it "can view all articles" do
get :index
expect(response).to be_successful
end
it "can not delete articles" do
Article.create!(valid_attributes)
expect {
delete :destroy, params: {
:id => @article.to_param
}
}.to change{ Article.count }.by(0)
end
end
context "when admin logged in" do
login_admin # ControllerMacros module method
it "can view all articles" do
get :index
expect(response).to be_successful
end
it "can delete articles" do
Article.create!(valid_attributes)
expect {
delete :destroy, params: {
:id => @article.to_param
}
}.to change{ Article.count }.by(-1)
end
end
end
end
Use Request instead of Controller Specs
RSpec and Rails are both encouraging specs be written for Request and not Controller. There is currently still support for Controller specs, but guessing that there will be more deprecation of Controller spec functionality down the road. Based on the release of RSpec 3.5:
The official recommendation of the Rails team and the RSpec core team is to write request specs instead.
- README - Request specs | rspec/rspec-rails GitHub
- RSpec 3.5 has been released! | RSpec blog
- RSpec โ Controller or Request Specs?
- When I use controller/request specs and when I donโt | Code with Jason
- Replacing RSpec controller specs, part 1: Request specs | Everyday Rails
- Replacing RSpec controller specs, part 2: Feature specs | Everyday Rails
References
- Controller specs | RSpec - Relish
- How To: Test controllers with Rails (and RSpec) | Devise Wiki
- Test helpers - Controller tests | Rails Setup
- Test helpers - Integration tests | Rails Setup
- Setup and test Rails 6.0 with RSpec, FactoryBot, and Devise
- A simple login test with RSpec, Devise, FactoryBot in Rails
- How I learned to test my Rails applications, Part 4: Controller specs | Everyday Rails