[RAILS] Write tests with Minitest

at first

The Ruby on Rails 5 Quick Learning Practice Guide that can be used in the field is written by RSpec because it is widely used in the development field. However, for those who are learning for the first time, RSpec may seem a little difficult.

Here, I will try Minitest, which is the standard testing framework of Ruby on Rails and allows you to write tests concisely.

現場で使える Ruby on Rails 5速習実践ガイド

Preparation

Added minitest to Gemfile. Minitest-reporters make it easier to see the test results.

# Gemfile
group :test do
  gem 'capybara'                     #Virtually operate the user's browser
  gem 'selenium-webdriver'
  gem 'webdrivers'

  gem 'minitest'                     #Rails standard testing framework
  gem 'minitest-reporters'           #Easy-to-read display of test results
end

With minitest-reporters, you can easily see the test results and Add login_helper so that you can test the login and logout of users.

# test/test_helper.rb
ENV['RAILS_ENV'] ||= 'test'
require_relative '../config/environment'
require_relative 'login_helper'
require 'rails/test_help'
require 'minitest/reporters'
Minitest::Reporters.use!

class ActiveSupport::TestCase
  # parallelize(workers: :number_of_processors)
  parallelize(workers: 1) #Click here if you get an error
  fixtures :all
end
# test/login_helper.rb
module LoginHelper
  def login_as(user)
    visit login_url
    fill_in 'mail address', with: user.email
    fill_in 'password', with: 'password'
    click_on 'log in'

    @current_user = user
  end

  def current_user
    @current_user
  end
end

Prepare a fixture. Fixture means built-in furniture in English. Rails will automatically load this fixture into your test database. There are more sophisticated gems such as Factory-bot for creating sample data, but here we will use fixtures that do not require any settings and can be introduced in a concise and easy-to-understand manner.

# test/fixtures/users.yml
#General user taro
taro:
  name: taro
  email: [email protected]
  password_digest: <%=BCrypt::Password.create('password', cost: BCrypt::Engine::MIN_COST)%>
  admin: true

#Admin admin
admin:
  name: admin
  email: [email protected]
  password_digest: <%=BCrypt::Password.create('password', cost: BCrypt::Engine::MIN_COST)%>
  admin: true

#You can also create ten users.
<% 1.upto(10) do |i| %>
user_<%= i %>:
  name: user_<%= i %>
  email: user_<%= i %>@example.com
  password_digest: <%=BCrypt::Password.create('password', cost: BCrypt::Engine::MIN_COST)%>
  admin: false
<% end %>

You can also set the association by writing user: taro for fixture.

# test/fixtures/tasks.yml
taro_task:
  name:Taro's task
  description:Various task descriptions
  user: taro

system test

The system test is a test when the user actually operates the web application with a browser. It may take some time to execute, but it is convenient because it can imitate the user's operation and if it fails, a screenshot will be taken automatically.

Creating a test

Rails implements generators to make it easier to create system tests.

% rails g system_test welcomes

By executing this command, a system test template will be created, so we will modify it a little.

# test/system/welcomes_test.rb
require "application_system_test_case"

class WelcomesTest < ApplicationSystemTestCase
  test "Taskleaf is displayed on the top page" do
    visit root_url
    assert_selector "h1", text: "Taskleaf"
  end
end

Run the test

You can run all system tests with the following command.

% rails test:system

To run some tests, use the following command:

% rails test test/system/welcomes_test.rb

The system test seems to have failed. スクリーンショット 0002-12-13 22.57.23.jpg

If it fails, a screenshot will be taken automatically.

/Users/mirai/rails_projects/


taskleaf/tmp/screenshots/
 failures_test_ Top page shows _Taskleaf_.png ```
 Is displayed, so you can check it in Finder.

 Based on the screenshot, fix the error and try again.

 ![スクリーンショット 0002-12-13 23.03.20.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96314/df26ef14-494f-2168-739c-8d03b333149b.jpeg)

 The system test passed successfully.

### User test

``` ruby
# test/system/users_test.rb
require "application_system_test_case"

class UsersTest < ApplicationSystemTestCase
  setup do
    @user = users(:taro)
  end

  test "If the password is correct, you can log in" do
    visit login_url
    fill_in 'mail address', with: @user.email
    fill_in 'password', with: 'password'
    click_on 'log in'

    assert_selector ".ui.success.message", text: "You are now logged"
  end

  test "If the password is different, you cannot log in" do
    visit login_url
    fill_in 'mail address', with: @user.email
    fill_in 'password', with: 'wrong password'
    click_on 'log in'

    assert_selector ".ui.error.message", text: "Email address or password is different"
  end
end

Task testing

Pre-preparing with the setup block is useful because it can be used forever in subsequent tests.

# test/system/tasks_test.rb
require "application_system_test_case"

class TasksTest < ApplicationSystemTestCase
  setup do
    @taro       = users(:taro)
    @jiro       = users(:jiro)

    @taro_task1 = tasks(:taro_task1)
    @taro_task2 = tasks(:taro_task2)
    @taro_task3 = tasks(:taro_task3)

    @jiro_task1 = tasks(:jiro_task1)
  end

  test "When you log in with Taro, the tasks created by Taro are listed." do
    login_as(@taro)
    visit tasks_path
    assert_text @taro_task1.name
    assert_text @taro_task2.name
    assert_text @taro_task3.name
  end

  test "When you log in with Taro, the tasks created by Taro are displayed in detail." do
    login_as(@taro)
    visit task_path(@taro_task1)
    assert_text @taro_task1.name
    assert_text @taro_task1.description
  end

  test "When I log in with Jiro, the tasks created by Taro are not displayed." do
    login_as(@jiro)
    visit tasks_path
    assert_no_text @taro_task1.name
  end

  test "You can register a task by entering a name on the new creation screen." do
    login_as(@taro)
    visit new_task_path
    fill_in 'name', with: 'New Taro's task'
    click_on 'register'

    assert_selector '.ui.success.message', text: 'New Taro's task'
    within 'table' do
      assert_text 'New Taro's task'
    end
  end

  test "If there is no name on the new creation screen, an error will be displayed" do
    login_as(@taro)
    visit new_task_path
    fill_in 'name', with: '   '
    click_on 'register'

    within '#error_explanation' do
      assert_text 'Please enter your name'
    end
  end

  test "You can edit your own tasks" do
    login_as(@taro)
    visit tasks_path
    click_on 'Editing', match: :first

    fill_in 'name', with: 'Edited Taro's task'
    click_on 'Update'

    assert_selector '.ui.success.message', text: 'Edited Taro's task'
    within 'table' do
      assert_text 'Edited Taro's task'
    end
  end

  test "You can delete your task" do
    login_as(@taro)
    assert_equal 3, current_user.tasks.count
    visit tasks_path
    click_on 'Delete', match: :first
    accept_confirm
    assert_selector '.ui.success.message', text: 'It has been deleted'
    assert_equal 2, current_user.tasks.count
  end
end

Email test

You can also test sending emails.

# test/mailers/task_mailer_test.rb
require 'test_helper'

class TaskMailerTest < ActionMailer::TestCase
  #Advance preparation
  setup do
    @user = users(:taro)
    @task = @user.tasks.create(name: 'Today's task',
                               description: 'Learn Ruby on Rails')
    @mail = TaskMailer.creation_email(@task)
  end

  test "A task creation completion email is sent" do
    #Test if email is sent
    assert_emails 1 do
      @mail.deliver_now
    end

    #Test if you sent the email you expected
    assert_equal "Task creation completion email", @mail.subject
    assert_equal [@user.email], @mail.to
    assert_equal ["[email protected]"], @mail.from
    assert_match "Today's task", @mail.html_part.body.to_s
    assert_match "Learn Ruby on Rails", @mail.html_part.body.to_s
    assert_match "Today's task", @mail.text_part.body.to_s
    assert_match "Learn Ruby on Rails", @mail.text_part.body.to_s
  end
end

Run your mailer test with the following command:

% rails test test/mailers

Finally

How was the introduction of the minitest that you can write concisely? We hope you find it useful.

reference

Rails Testing Guide (https://railsguides.jp/testing.html)

Recommended Posts

Write tests with Minitest
Write tests for JavaFX applications with TestFX
Write solidly with PhpStorm
Write RestController tests quickly with Spring Boot + Spock
Various method tests with MockRestServiceServer
Java unit tests with Mockito
Write a Reactive server with Micronaut
Perform automatic screen tests with Selenide + XlsMapper