[RUBY] About RSpec directory structure and role for each spec

Introduction

Regarding the test framework of the web application currently being created, we are migrating from Minitest to RSpec in consideration of Last created article. At that time, I felt that it was necessary to be aware of the types of tests that Minitest was not very aware of. How to write a test depends on whether the test is a UI test, a controller test, or a model test. This article briefly summarizes RSpec's directory structure and how to write code for each test type. I referred to it → Introduction to RSpec that can be used, Part 1 "Understanding the basic syntax and useful functions of RSpec" Everyday Rails-Introduction to Rails Testing with RSpec

RSpec main directories

The type of RSpec test is called Spec. Specs are usually placed in a canonical directory structure that describes their purpose.

** [Main RSpec directory structure] **

spec --- models      | | ー requests      | | ー features      | | ー helpers      | | ー mailers      | | ー system

About the main role of Spec

Here, we will introduce the roles of ** Model Spec **, ** Request Spec **, ** Feature Spec **, and ** System Spec **.

Model Spec Model Spec tests Rails models such as validation. Check with the sample code below.

spec/models/user_spec.rb


RSpec.describe User, type: :model do

  describe 'username' do
    it 'If blank, it is in an invalid state' do
      user = User.new( name: '  ',
                       email: '[email protected]',
                       password: 'password',
                       password_confirmation: 'password')
      expect(user).to_not be_valid
    end

    it 'If it is too long, it is in an invalid state' do
      user = User.new( name: 'a' * 51,
                       email: '[email protected]',
                       password: 'password',
                       password_confirmation: 'password')
      expect(user).to_not be_valid
    end
  end
end

I will check the contents one by one.

-Specify spec with type:: model. We are testing the user model here.

· describe groups the expected results. It declares "testing the user model" and "testing the user name" in it.

-`ʻUser.new`` creates a user.

-ʻit`` is grouped in units smaller than `` describe`` called ** example **. You can have multiple expectations within ʻit. However, if it fails in the middle, it will not flow beyond that, so basically one expectation for each `ʻit is recommended.

ʻExpect`` describes the expectation (expectation). ʻexpect (user) .to_not be_validis testing that" user is not valid? " One of the advantages of RSpec is that you can write tests like in English. The to_not be_valid`` part is called ** matcher ** and there are various types. Other matchers can be found at here.

Request Spec The Request Spec is according to the Official Documentation (https://relishapp.com/rspec/rspec-rails/v/4-0/docs/request-specs/request-spec) "via the full stack including routing". , Designed to drive operation without stubs [^ 1]. " The point is server-side testing. Request Spec allows you to use HTTP methods (get, post, delete, etc.) when testing the response of the controller.

spec/requests/access_to_users_spec.rb


RSpec.describe "AccessToUsers", type: :request do 

  describe 'Access restrictions for users who are not logged in' do
    it 'Delete user' do
      user = User.create( name: 'kojiro',
                          email: '[email protected]',
                          password: 'password',
                          password_confirmation: 'password')
      expect {
              delete user_path(user)
              }.to change(User, :count).by(0)
    end
  end
end

Here we use the delete method to test that a non-logged-in user deletes a user but it is not reflected. ```expect {delete user_path (user)} .to change (User,: count) .by (0) `` means that when accessing delete user_path (user), the difference in the number of users before and after access is 0. Predict. "

Feature Spec Feature Spec is a UI test. Official documentation recommends using System Spec, which has similar functionality from RSpec 3.7. doing.

System Spec System Specs, like Feature Specs, are primarily UI tests. You can write an E2E (end-to-end) test to run on your browser. This is a front test. Also, by default, we are running tests using the Chrome browser. Use ** Capybara ** to simulate browser activity. We will check what kind of description it will be with the sample code below.

spec/systems/user_logins_spec.rb


RSpec.describe "UsersLogins", type: :system do
  it 'Valid login' do
    user = User.create( name: 'kojiro',
                        email: '[email protected]',
                        password: 'password',
                        password_confirmation: 'password')
    visit login_path
    fill_in 'mail address', with: '[email protected]'
    fill_in 'password', with: 'password'
    click_button 'Login'
    expect(current_path).to eq user_path(user)
  end
end

I will check the contents one by one.

-First, create a user with `ʻUser.create`` and save it.

-Methods such as visit, fill_in, and click_button are Capybara's domain-specific languages called DSL.

  1. visit represents a visit to the page. Use visit login_path to go to the login page.
  2. fill_in represents the input of characters in the text box. In fill_in'email address', with:'[email protected]', you have entered'[email protected]' in the text box named'email address'.
  3. click_button Represents a button click.

Other DSLs are listed here [https://github.com/teamcapybara/capybara#the-dsl).

· `ʻExpect (current_path) .to eq user_path (user) `` tests" whether the current path is the same as user_path (user) (user details) ".

In addition, when the test fails, the System spec displays a screenshot of the failed part along with an error message of the failed content. As a test, change the ```user_path (user) of the expectation to login_path`` and run the test. Then the following output was output.

Failures:

  1)UsersLogins Valid login, logout
     Failure/Error: expect(current_path).to eq login_path
     
       expected: "/login"
            got: "/users/1"
     
       (compared using ==)
     
     [Screenshot]: /(Program path)/myapp/tmp/screenshots/failures_r_spec_example_groups_users_logins_Valid login, logout_119.png

     
     # ./spec/system/users_login_spec.rb:14:in `block (2 levels) in <top (required)>'

failures_r_spec_example_groups_users_logins_有効なログイン、ログアウト_119.png

As you can see in the screenshot, you are seeing the ʻuser_path (user) `(user details screen) instead of the login_path (login screen) you expected the results to be.

Summary

By the way, in Request Spec, Capybara cannot be used, and in Feature Spec, HTTP method cannot be used. It will be necessary to determine whether the test you are about to implement is server-side or front-side.

[^ 1]: A stub is a substitute for a submodule that a module calls when testing a module in a computer program. ([wiki](https://ja.wikipedia.org/wiki/%E3%82%B9%E3%82%BF%E3%83%96#:~:text=%E3%82%B9%E3% 82% BF% E3% 83% 96% EF% BC% 88stub% EF% BC% 89% E3% 81% A8% E3% 81% AF% E3% 80% 81,% E7% 94% A8% E3% 81 % 84% E3% 82% 8B% E4% BB% A3% E7% 94% A8% E5% 93% 81% E3% 81% AE% E3% 81% 93% E3% 81% A8% E3% 80% 82 & text =% E9% 80% 86% E3% 81% AB% E4% B8% 8A% E4% BD% 8D% E3% 83% A2% E3% 82% B8% E3% 83% A5% E3% 83% BC% E3% 83% AB% E3% 81% AE,% E3% 82% A6% E3% 82% A7% E3% 82% A2% E3% 81% AE% E5% A0% B4% E5% 90% 88% EF From% BC% 89% E3% 81% A8% E5% 91% BC% E3% 81% B6% E3% 80% 82)) Here, Rails works in the test without using a substitute for its lower module Is able to drive.

Recommended Posts

About RSpec directory structure and role for each spec
About for statement and if statement
[For beginners] About lambda expressions and Stream API