[RUBY] Introduction to RSpec 5. Controller specs

Continuation of Last time

Controller testing in RSpec can be replaced by model testing and integration testing, so there aren't many opportunities to use it. Recently, with the introduction of system specs, which are more advanced integration tests, the number of controller specs has been further reduced. However, I think that it may be touched by the maintenance of the existing program, so I will summarize it only lightly.

Static controller specs

Tests if the status of the response is successful. First, generate a spec file.

$ rails g rspec:controller home

spec/controllers/home_controller_spec.rb will be generated.

Test if the controller returns a successful response to the request.

spec/controllers/home_controller_spec.rb


require 'rails_helper'

RSpec.describe HomeController, type: :controller do
  de
  describe "#index" do
    it "responds successfully" do
      get :index
      expect(response).to be_success
    end
  end
end

The response is an object that holds all the application data that should be returned to the browser. be_success is a matcher that checks if the response status is successful (200) or not.

You can use have_http_status if you want to see a specific HTTP response code.

spec/controllers/home_controller_spec.rb


require 'rails_helper'

RSpec.describe HomeController, type: :controller do
  de
  describe "#index" do
    it "responds a 200 response" do
      get :index
      expect(response).to have_http_status "200"
    end
  end
end

Controller specs that require authentication

I will write the specifications of the projects controller. This controller has a common CRUD structure that allows only logged-in users to work with projects associated with them.

$ rails g rspec:controller project

Preparation before the test

As before, we'll first test for a successful response, but controller actions that require authentication need to be prepared in advance.

There are two main preparations,

  1. Loading Devise helper module
  2. Definition of helper method for login is. I will explain step by step.

Loading Devise helper module

Devise provides a helper that simulates a user's login state for controller actions that require authentication, and uses this helper when running tests. However, RSpec doesn't load this helper by default, so I'll add some settings to make it available.

spec/rails_helper.rb


  #Add this one line
  config.include Devise::Test::ControllerHelpers, type: :controller

With this setting, you can use Devise's helper module in the controller specifications.

Definition of helper methods for login

If you send a request while the user is not logged in, you will get a redirect (302) back to the login page, so you need to be logged in as a test setup.

Even if you describe the login process in the specifications, it will work, but since the login process is performed frequently, it is a must to create a helper now.

#Login process tailored to each app
def sign_in(user)
  cookies[:auth_token] = user.auth_token
end

test

Since the processing results of the Projects controller differ between the logged-in user and the guest user, prepare multiple test scenarios.

spec/controllers/projects_controller_spec.rb


require 'rails_helper'

RSpec.describe ProjectsController, type: :controller do
  de
  describe "#index" do

    context "guest" do
      it "returns a 302 response" do
        get :index
        expect(response).to have_http_status "302"
      end

      it "redirects to the sign_in page" do
        get :index
        expect(response).to redirect_to "users/sign_in"
      end
    end

    context "logged_in" do
      before do
        @user = FactoryBot.create(:user)
      end
    
      it "responds successfully" do
        sign_in @user
        get :index
        expect(response).to be_success
      end

      it "responds a 200 response" do
        sign_in @user
        get :index
        expect(response).to have_http_status "200"
      end
    end
  end
end

Test user input

We will also test POST, PATCH, and DESTROY requests using the create action as an example. Don't forget input errors and tests.

spec/controllers/projects_controller_spec.rb


describe "#create" do
  context "guest" do
    it "returns a 302 response" do
      project_params = FactoryBot.attributes_for(:project)
      post :create, params: { project: project_params }
      expect(response).to have_http_status "302"
    end

    it "redirects to the sign_in page" do
      project_params = FactoryBot.attributes_for(:project)
      post :create, params: { project: project_params }
      expect(response).to redirect_to "/users/sign_in"
    end
  end

  context "logged_in" do
    before do
      @user = FactoryBot.create(:user)
    end

    context "vaild attributes" do
      it "adds a project" do
        project_params = FactoryBot.attributes_for(:project)
        sign_in(@user)
        expect{
          post :create, params: { project: project_params }
        }.to change(@user.projects, :count).by(1)
      end
    end

    context "invaild attributes" do
      it "dose not add a project" do
        project_params = FactoryBot.attributes_for(:project, :invalid)
        sign_in(@user)
        expect{
          post :create, params: { project: project_params }
        }.to_not change(@user.projects, :count)
      end
    end
  end
end

Handle non-HTML output

We will also look at testing the process of returning data in formats such as CSV and JSON. With the code to send the request

format: :json

Specify the format with

expect(response.content_type).to eq "application/json"

You can test by specifying the format of the data returned in.

Continued

Recommended Posts

Introduction to RSpec 5. Controller specs
Introduction to RSpec 3. Model specs
Introduction to RSpec 1. Test, RSpec
Introduction to RSpec 2. RSpec setup
Introduction to RSpec 6. System specifications
Introduction to Ruby 2
Rspec introduction memo_Rails
Introduction to SWING
Introduction to web3j
Introduction to Micronaut 1 ~ Introduction ~
[Java] Introduction to Java
Introduction to migration
Introduction to java
Introduction to Doma
How to write an RSpec controller test
Introduction to JAR files
Introduction to Ratpack (8)-Session
Introduction to bit operation
Introduction to Ratpack (6) --Promise
Set RSpec to DRY
Introduction to Ratpack (9) --Thymeleaf
Introduction to PlayFramework 2.7 ① Overview
Introduction to Android Layout
Introduction to design patterns (introduction)
Introduction to Practical Programming
Introduction to javadoc command
Introduction to jar command
Introduction to Ratpack (2)-Architecture
Introduction to lambda expression
Introduction to java command
Introduction to Keycloak development
Introduction to javac command
Introduction to RSpec 4. Create test data with Factory Bot
Introduction to Design Patterns (Builder)
Dynamically assign Controller to JavaFX-fxml
Introduction to Android application development
Introduction to Ratpack (5) --Json & Registry
Introduction to Metabase ~ Environment Construction ~
Introduction to Ratpack (7) --Guice & Spring
(Dot installation) Introduction to Java8_Impression
Introduction to Design Patterns (Composite)
Introduction to Micronaut 2 ~ Unit test ~
Introduction to JUnit (study memo)
Introduction to Spring Boot ① ~ DI ~
Introduction to design patterns (Flyweight)
[Java] Introduction to lambda expressions
Introduction to Spring Boot ② ~ AOP ~
Introduction to Apache Beam (2) ~ ParDo ~
[Ruby] Introduction to Ruby Error statement
Introduction to EHRbase 2-REST API
Introduction to design patterns Prototype
GitHub Actions Introduction to self-made actions
[Java] Introduction to Stream API
Introduction to Design Patterns (Iterator)
Introduction to Spring Boot Part 1
Introduction to Ratpack (1) --What is Ratpack?
XVim2 introduction memo to Xcode12.3
Introduction to RSpec-Everyday Rails Summary-
Introduction to Design Patterns (Strategy)
[Introduction to rock-paper-scissors games] Java
[Introduction to Java] About lambda expressions