65
44

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Ruby on RailsAdvent Calendar 2018

Day 20

RailsチュートリアルのMinitestをRSpecに翻訳するvol.1

Last updated at Posted at 2018-12-19

投稿に寄せて

本記事は、Railsエンジニアの登竜門である Railsチュートリアル にて紹介されている
テストフレームワークである MinitestRSpec に書き直していきます。
おそらく、Railsエンジニアを目指す方々が実際の業務で扱うテストフレームワークは
Minitest に比べて、 RSpecの方が断然多いのではないでしょうか!
このことからもRSpecを学ぶメリットは十分にあると思います。
本記事が、Rails勉強中の方の参考になれば幸いです。

概要

本記事はRailsチュートリアル(Rails 5.1)の第3章以降の本格的アプリ開発の部分を対象として、
MinitestからRSpecへのリファクタリングをおこなっていきます。

前提

Railsチュートリアル第3章と同じ条件で rails new したアプリの土台がすでにあること
https://railstutorial.jp/chapters/static_pages?version=5.1#sec-slightly_dynamic_pages

RSpecで開発をする準備

ここでRSpecでテストを書いていく前にRSpecのセットアップをしていきましょう!

必要Gemリスト

  gem 'rspec-rails'
  gem 'spring-commands-rspec'
  gem 'factory_bot_rails'
  gem 'faker'
  gem 'capybara'
  gem 'database_cleaner'
  gem 'launchy'
  gem "selenium-webdriver"

各Gemの解説

rspec-rails
RSpecを使用するために必要なgem。

spring-commands-rspec 
bin/rspecのコマンドを実行するときに必要になるもの。
rspecはbin/コマンドをつけることでSpringというRailsに組み込まれているアプリを起動させて処理を高速化出来る。
rspec自体はrspecと打ち込むだけでも起動可能。

factory_bot_rails 
テストの際に使用するデータを作成するためのもの。

faker 
実在しそうな名前でダミーデータを作成するためのもの。

capybara
アプリケーション操作をRubyで設定して、ユーザがアプリケーションを使っているかのようにページを遷移させて、不具合検証するためのもの。主に画面に関わる結合テストで使用する。

database_cleaner
逐一テストデータを削除するためのもの。

launchy 
Capybaraでテスト中に、現在どのページを開いているのか確認するためのもの。

selenium-webdriver 
複数テストの並行実行用。

実際のGemfile

source 'https://rubygems.org'

gem 'rails',        '5.1.4'
gem 'puma',         '3.9.1'
gem 'sass-rails',   '5.0.6'
gem 'uglifier',     '3.2.0'
gem 'coffee-rails', '4.2.2'
gem 'jquery-rails', '4.3.1'
gem 'turbolinks',   '5.0.1'
gem 'jbuilder',     '2.7.0'

group :development, :test do
  gem 'sqlite3', '1.3.13'
  gem 'byebug',  '9.0.6', platform: :mri
  gem 'spring-commands-rspec'
end

group :development do
  gem 'web-console',           '3.5.1'
  gem 'listen',                '3.1.5'
  gem 'spring',                '2.0.2'
  gem 'spring-watcher-listen', '2.0.1'
  gem 'pry-rails'
  gem 'pry-byebug'
  gem 'pry-doc'
end

group :test do
  gem 'rails-controller-testing', '1.0.2'
  gem 'minitest-reporters',       '1.1.14'
  gem 'guard',                    '2.13.0'
  gem 'guard-minitest',           '2.4.4'
  gem 'rspec-rails'
  gem 'factory_bot_rails'
  gem 'faker'
  gem 'capybara', '~> 2.13'
  gem 'database_cleaner'
  gem 'launchy'
  gem 'selenium-webdriver'
end

group :production do
  gem 'pg', '0.20.0'
end

gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]

下準備

  • とりあえず bundle install
bundle install --path vendor/bundle
  • bin/rspecファイルを生成
bundle exec spring binstub rspec
  • RSpecの設定ファイル群を生成
rails generate rspec:install
  • .rspecに以下の項目を追記して、テスト結果出力をドキュメント形式に変更する
<中略>
--format documentation
  • application.rbを編集して、無駄なファイルが生成されないようにする
require_relative 'boot'

require 'rails/all'

# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)

module RailsTutorial514
  class Application < Rails::Application
    # Initialize configuration defaults for originally generated Rails version.
    config.load_defaults 5.1

    config.generators do |g|
      g.test_framework :rspec,
                       fixtures: true,
                       view_specs: false,
                       helper_specs: false,
                       routing_specs: false,
                       controller_specs: true,
                       request_specs: false
      g.fixture_replacement :factory_bot, dir: "spec/factories"
    end
  end
end
  • RSpecを実行出来るかコマンドで確認
$ bin/rspec

No examples found.

Finished in 0.00018 seconds (files took 0.06751 seconds to load)
0 examples, 0 failures

準備が出来たら実際にやっていこう

第3章の実装は下記のRailsチュートリアルの通り実装していく前提で進めます。
ここではテスト以外の実装には触れません。
https://railstutorial.jp/chapters/static_pages?version=5.1#cha-static_pages

3.3.1 最初のテスト

※ Railsチュートリアルの項目3.3.1を参照

テストすべき項目

  • Home画面が正常に表示されること
  • Help画面が正常に表示されること

Minitestで書いた場合

test/controllers/static_pages_controller_test.rb
require 'test_helper'

class StaticPagesControllerTest < ActionDispatch::IntegrationTest

  def setup
    @base_title = "Ruby on Rails Tutorial Sample App"
  end

  test "should get home" do
    get static_pages_home_url
    assert_response :success
  end

  test "should get help" do
    get static_pages_help_url
    assert_response :success
  end
end

```

### RSpecで書いた場合(画面表示周りのRSpecであるFeatureSpecで書く)

#### FeatureSpec(フィーチャースペック)の説明
FeatureSpecとはRailsのテストフレームワークのRSpecで行われるテストの種類の1つで、ブラウザ上の操作をシミュレートして実行結果を検証するテストのことです。
一般的には「統合テスト」や「エンドツーエンドテスト(E2Eテスト)」といった名称で呼ばれています。

ざっくりイメージで言うと、モデルとコントローラーがうまく一緒に動作することで表示も正しいものであることを検証するテストという理解で良いと思います!

以下は、今回Minitestから書き直したファイルです。

```/spec/features/static_pages_spec.rb
require 'rails_helper'

describe 'Home' do
  specify '画面の表示' do
    visit '/static_pages/home'
    expect(page).to have_css('h1', text: 'Sample App')
  end
end

describe 'Help' do
  specify '画面の表示' do
    visit '/static_pages/help'
    expect(page).to have_css('h1', text: 'Help')
  end
end
```

#### テストコードの補足
>`describe '〇〇' do` の〇〇の部分にテストしたい対象を記載する

>`specify '〇〇' do` の部分にテストしたい内容の詳細を記載する

>`visit 'URL'` 'URL'の部分に検証したい画面のURLを記載する

>`expect(page).to` はvisitしたカレントページを対象とするという意味

>`have_css` はテストの検証したい内容を計るためのメソッドで「マッチャ」(マッチを計るため)と呼ばれるものの1つです。 

>`have_css('h1', text: 'Help')` で HTMLのh1要素の内容が `Help` かどうかを検証している

>`expect(page).to have_css('h1', text: 'Help')` でカレントページはh1要素のテキストとしてHelpを持っているかを検証している


#### 実行コマンド(このコマンドでRSpecのテストファイルに記載したテストを実行出来る)

```ruby
bundle exec rspec spec/features/static_pages_spec.rb
```

#### 実行結果

![image.png](https://qiita-image-store.s3.amazonaws.com/0/222024/40d9f094-5e68-700a-e6d1-889dce94a100.png)


## 3.3.2 RED 〜 3.3.3 GREENまで

#### テストすべき項目
- Home画面が正常に表示されること
- Help画面が正常に表示されること
- About画面が正常に表示されること

#### Minitestで書いた場合

````test/controllers/static_pages_controller_test.rb
require 'test_helper'

class StaticPagesControllerTest < ActionDispatch::IntegrationTest

  def setup
    @base_title = "Ruby on Rails Tutorial Sample App"
  end

  test "should get home" do
    get static_pages_home_url
    assert_response :success
  end

  test "should get help" do
    get static_pages_help_url
    assert_response :success
  end
  
  test "should get about" do
    get static_pages_about_url
    assert_response :success
  end
end

```

#### RSpecで書いた場合(画面表示周りのRSpecであるFeatureSpecで書く)

```/spec/features/static_pages_spec.rb
require 'rails_helper'

describe 'home' do
  specify '画面の表示' do
    visit '/static_pages/home'
    expect(page).to have_css('h1', text: 'Sample App')
  end
end

describe 'help' do
  specify '画面の表示' do
    visit '/static_pages/help'
    expect(page).to have_css('h1', text: 'Help')
  end
end

describe 'about' do
  specify '画面の表示' do
    visit '/static_pages/about'
    expect(page).to have_css('h1', text: 'About')
  end
end
```

```routes.rb
Rails.application.routes.draw do
  get 'static_pages/home'
  get 'static_pages/help'
  get  'static_pages/about'
  root 'application#hello'
end
```

#### 実行結果

![image.png](https://qiita-image-store.s3.amazonaws.com/0/222024/4538df34-30fa-3cbe-4983-66750f5ec34f.png)

## 3.4 少しだけ動的なページ

レイアウトファイル(Railsアプリの基盤となるテンプレート)の役割をよりわかりやすく説明するために、最初に レイアウトファイルの`application.html.erb` の無効化をする

```ruby
 mv app/views/layouts/application.html.erb layout_file
```

## 3.4.1 タイトルをテストする(Red) 〜 3.4.2 タイトルを追加する(Green)

#### テストすべき項目
- Home画面タイトル "Home | Ruby on Rails Tutorial Sample App" が正常に表示されること
- Help画面タイトル "Help | Ruby on Rails Tutorial Sample App" が正常に表示されること
- About画面タイトル "About | Ruby on Rails Tutorial Sample App" が正常に表示されること

#### Minitestで書いた場合

```test/controllers/static_pages_controller_test.rb
require 'test_helper'

class StaticPagesControllerTest < ActionDispatch::IntegrationTest

  test "should get home" do
    get static_pages_home_url
    assert_response :success
    assert_select "title", "Home | Ruby on Rails Tutorial Sample App"
  end

  test "should get help" do
    get static_pages_help_url
    assert_response :success
    assert_select "title", "Help | Ruby on Rails Tutorial Sample App"
  end

  test "should get about" do
    get static_pages_about_url
    assert_response :success
    assert_select "title", "About | Ruby on Rails Tutorial Sample App"
  end
end
```

#### RSpecで書いた場合(画面表示周りのRSpecであるFeatureSpecで書く)

- ここでテストの内容もタイトルの内容を検証するように変更

```/spec/features/static_pages_spec.rb
require 'rails_helper'

describe 'Home' do
  specify 'タイトル内容の表示' do
    visit '/static_pages/home'
    expect(page).to have_title 'Home | Ruby on Rails Tutorial Sample App'
  end
end

describe 'Help' do
  specify 'タイトル内容の表示' do
    visit '/static_pages/help'
    expect(page).to have_title 'Help | Ruby on Rails Tutorial Sample App'
  end
end

describe 'About' do
  specify 'タイトル内容の表示' do
    visit '/static_pages/about'
    expect(page).to have_title 'About | Ruby on Rails Tutorial Sample App'
  end
end
```

#### テストコードの補足

>`have_title` もテストの検証したい内容を計るためのメソッドで「マッチャ」(マッチを計るため)と呼ばれるものの1つです。

## 実行結果

![image.png](https://qiita-image-store.s3.amazonaws.com/0/222024/cc869c04-855e-0390-1531-8fdeefd5f9b1.png)

## 3.4.4 ルーティングの設定

### ルーティングの変更

`static_pages#home` root( `/` )のルーティングに変更

```config/routes.rb
Rails.application.routes.draw do
  root 'static_pages#home'
  get  'static_pages/home'
  get  'static_pages/help'
  get  'static_pages/about'
end
```

#### Minitestで書いた場合

```test/controllers/static_pages_controller_test.rb
require 'test_helper'

# rootのURLにアクセスするテストを追加
class StaticPagesControllerTest < ActionDispatch::IntegrationTest
  test "should get root" do
    get FILL_IN
    assert_response FILL_IN
  end

  <中略>
end
```

#### RSpecで書いた場合(FeatureSpec)

```/spec/features/static_pages_spec.rb
require 'rails_helper'

# Home画面をrootとしてそこにアクセスするテストに修正する
describe 'Home' do
  specify 'タイトル内容の表示' do
    visit '/' # ここを変更
    expect(page).to have_title 'Home | Ruby on Rails Tutorial Sample App'
  end
end

<中略>
```

## 実行結果

- Home画面をrootに変わったテストも通り、既存のテストも通ることを確認

![image.png](https://qiita-image-store.s3.amazonaws.com/0/222024/7833a938-1980-90f0-54e9-a1e072f6fd43.png)

## 最後に

いかがだったでしょうか!
自分の周りでRSpecを慣れていきたい!もっと知りたい!!という声をよく聞きます。

実を言うと自分も普段Railsエンジニアをしているものの、RSpecをイチからセットアップしたり、なにも無いところからテストをゴリゴリ書いていくことってあんまりないんですよね...
(既存のコードを参考に追加のテストを書いてしまうこともある...)
そういった背景もあり、イチからテストのセットアップをしてテストコードを書く練習として、RailsチュートリアルのMinitestRSpecへ翻訳させて頂きました。

時間を見つけて、第3章以降も翻訳を試みてみます。
初心者でRSpecをこれから練習したい!という方の良い回答サンプルになるような続編を頑張って書こうと思うので、続きも購読のほど、宜しくお願いします。 

## 追記
 Rails5.1以降ではFeatureSpecに代わって、SystemSpecというFeatureSpecのテストが推奨されるようになっています。普段の業務で使っていることから、当たり前のようにFeatureSpecで書いてしまいましたが、書いた後で気づきました... 
65
44
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
65
44

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?