【Rails】Rspecでテストコードを書く【78日目】

【学習内容】


・テストについて
・Rspec

【テストについて】


自動テストは、コードが変更されるたびに自動テストを動かしてエラーの有無を確認することで、コードに意図しない不具合や挙動変更が混入することを防ぐことができます。


プログラムが正しく動作しているかどうかを確認するプログラムを作り、それを実行して想定どおりの動作をしているかを確認をしているかを確認することを指します。


【テストを書くメリット】


十分な自動テストを備えるためには開発を進めるたびに開発した機能を確認するためのテストをセットで書くことが大切です。


しかし、実際は面倒だと感じることが多いです。(僕も早く進めたいです)
これからテストを実施することのメリットを書いていきます。

①テスト全体にかかるコストの削減
リリース前に機能全体を人手でテストするというやり方でもなんとかうまくいこともありますが、問題はリリース後に機能の追加などをおこなった際は、新機能以外の部分も再度確認する必要性が生じます。
ここで自動テストを備えていれば、動作確認の大部分をテストに任せることができ、全体のコスト削減に繋がります。

②変更をフットワーク軽く行える
逆説的に、自動テストがないとコード変更が入ること自体が大きなリスクになりえます。
自動テストによって新しい変更を追加することを頻繁に行うのは困難になります。


③環境のバージョンアップやリファクタリングの必須条件
Railsのアプリケーションを長期に渡って開発・運用していくような場合には、利用しているRubyやRails、各種gemのバージョンを積極的に上げていくことが非常に重要です。


バージョンアップを行うにあたって、既存機能が想定どおりに動作しているかを自動的に確認できるテストが備わっているかどうかは、死活問題といっても過言ではありません。


テストがあれば、実際にバージョンアップしてみて自動テストの落ち具合を確認し。問題のある箇所を手当するというような手順でスムーズにバージョンアップできます。


同様にアプリケーションの挙動は変えないで内部のコードをリファクタリングするときにも大いに役立ちます。


④仕様変更の影響の大きさを簡単に把握できる


あらかじめ十分な量のテストが書かれていれば、本体コードだけを変更してテストに渡すことで、その変更がシステム全体にどのような影響を与えるか、テストの落ち方から検討することができます。


⑤仕様を記述したドキュメントとして機能する


テストは動作確認のためだけにあるのではなく、期待している動作の詳細を開発チーム内で共有する手段にもなりえます。


例として、ユーザーの入力値として、なにをもって正しいと想定しているのか、エラー時にはどんなことが起きるのか、厳密に読み取ることができます。


要はRspecは実際に動く仕様書としての側面を持ちます。
他にもメリットはありますが、残りは効率の良さとか、テストを意識することで、結果的に良いコードになるとかの話なので、ここらで止めておきます。


【Rspecについて】


Rspecは、テストが動く仕様書として機能し、開発現場で広く利用されているテスティングフレームワークです。


【Capybara】


Rspecなどのテスティングライブラリと合わせて使用するもので、Webアプリケーションのブラウザ操作をシュミレーションできたり、実際のブラウザ操作と組み合わせてJSの動作まで含めたテストが可能です。

【FactoryBot】

テスト用データの作成をサポートするgemです。
DSLを使って似たデータを効率よく定義することができます。


【テストの種類】

一口にテストといってもRailsのテストには豊富な種類があります。

□全体的なテスト
・システムテスト
 ブラウザを通してアプリケーションの挙動を外部的に確認する
・結合テスト
 いろいろな種類の連携が想定どおりに動くかを確認するテスト
・機能テスト
 コントローラー単位のテスト

□個々の部品のテスト
・モデル
・ルーティング
・ビュー
・ヘルパー
・メーラー
・ジョブ


この中で特に重要なのは、システムテストです。
システムテストは、テストの粒度として1番外側(ユーザー側)に位置しているテストだからです。


今回はこのシステムテストを実施します。
また、現場では他にもモデルテスト、結合テスト、ルーティング、メーラー、ジョブテストなどが実行されています。

【System Specを書くための準備】


・RSpecのインストール


■gemfile

group :test do
…
gem ‘rspec-rails’, ‘-> 3.7end
$bundle


下記のコマンドを実行すると、RSpecに係る関連ファイルが自動で作成されます。

$bin/rails g rspec :install


Railsアプリケーションを作成したときに自動で作成されたtestディレクトリを削除します。RSpecではこのファイルは使用しません。

$ rm –r ./test

・Capybaraの初期準備


Capybaraのgemは最初のrails newの段階で既にインストールされています。
RSpecでCapybaraを使用するには「require ‘capybara/rspec’」と記載します。


また、「driven_by :selenium_chorme_headless」では、SystemSpecを実行するドライバの設定をします。


ドライバとはCapybaraを使ったテストにおいてブラウザ相当の機能を利用するのに必要なプログラムで、今回は処理が高速なHeadlessChormeを使用します。


ヘッドレスブラウザについてはこちらを参考にしてください。
https://logzitsu.tlog.work/headless-chrome/

spec/spec_helper.rb


# See http://rubydoc........
require ‘capybara/rspec’
RSpec.configure do |system| do
config.before(:each, type: :system) do
driven_by :selenium_chorme_headless
end
#rspec-expectation config goes here, you can use an alternate

・FactoryBotのインストール


■gemfile

group :development :test do
# Call ‘byebug’ anywhere in the code to stop execute and get a debugger console
gem ‘byebug’, platforms: [:mrl, :mingw, :x64_mingw]
gem ‘factory_bot_rails’, ‘-> 4.11end

$bundle

これで準備完了です。

【RSpecの基本形の例】


基本的には下記のような雰囲気で書いていきます。
describeやcontextをネストすることも可能です。


■Specの書き方

describe [仕事を記述する対象(テスト対象)], type: [Specの種類] do
context [ある状況・状態] do
before do
[事前準備]
end
it [仕様の内容(期待の概要)] do
[期待する動作]
end
end
end

■SystemSpecの例


describe ‘~機能’, type: :system do
describe ‘登録’ do 
context ‘○○の場合’ do
before
# { context内を確認するのに必要な } 事前準備
end
it ‘△△する’ do
# 期待する動作
end
end
context ‘××の場合’ do
before do
#{ context 内を確認するのに必要な }事前準備
end
it ‘○○する’ do
# 期待する動作
end
end 
end


【FactoryBotでテストデータを作成できるように準備する】


一般的にRailsアプリケーションを動かすには、DBに入っているデータを利用してCRUD機能の実現等を図ります。


すなわち、DBの中にデータが入ってないと話にならないということです。
Railsでは、テスト目的で利用するDBを他の目的で使うDBとは切り離しており、「development環境」、「test環境」、「production環境」の3つの環境があります。

一目瞭然ですが、この3つの環境のうちテストで使用する環境は「test環境」です。

テストを実施するにあたり、test環境にテストの前提となるデータをテストケース実施の前に投入し、次のテストケースを実施するまでに元に戻すということが必要になります。

1. FactoryBotでデータを作成するための「テンプレート」を用意する
2. SystemSpecの適切なbeforeなどで、FactoryBotのテンプレートを利用してtest用DBにデータを入れる
3.次のテストケースに進む前にデータ状態を戻す(SystemSpecがやってくれる)

この一連の動作を実現させるのが、FactoryBotです。

まずはUserファクトリから作成します。

■spec/factories/users.rb


FactoryBot.define do
factory :user do
name { ‘テストユーザー’ }
email { ‘test@example.com’ }
password { ‘password’ }
end
end


factoryのブロックには、属性の内容を示すハッシュを渡します。

■spec/factories/task.rb


FactoryBot.define do
factory :task do
name { 晩御飯のしたくをする’ }
email { ‘ネギと豆腐と大根を買う’ }
user
end
end


「user」とだけ書かれている意味はuserモデルとtaskモデルの関連付けをしていることを表しています。


【タスクの一覧表示機能のSystem Spec】


ここから実際にテストコードを書いていきます。
テストの内容は、「一覧画面に遷移したら作成済みのタスクが表示されている」というSpecです。


まずは、コメントアウトでSpecの大枠を作ります。
また、systemディレクトリは新規作成します。


■spec/system/tasks_spec.rb


require ‘rails_helper’
describe ‘タスク管理画面一覧’, type: :system do
describe ‘一覧表示機能’ do
before do
# ユーザーAを作成しておく
# 作成者がユーザーAであるタスクを作成しておく
end
context ‘ユーザーAがログインしているとき’ do
before do
# ユーザーAでログインする
end
it ‘ユーザーAが作成したタスクが表示される’ do
# 作成済みのタスクの名称が画面上に表示されていることを確認
end 
end
end
end


beforeのブロックの中に記載するのは、前提条件です。
1つ目のbeforeでユーザーを作成し、2つ目のbeforeでログインをします。
そして、itでタスクの表示を確認するという流れです。
これから1つ1つのコメントを具体化していきます。


【ユーザーAを作成する】


FactoryBot.createメソッドで、先ほど用意した:userファクトリを設定して、Userオブジェクトの作成、登録を行います。


■spec/system/tasks_spec.rb


require ‘rails_helper’
describe ‘タスク管理画面一覧’, type: :system do
describe ‘一覧表示機能’ do
before do
user_a = FactoryBot.create(:user, name: ‘ユーザーA’, email: ‘a@example.com’)
# 作成者がユーザーAであるタスクを作成しておく
end
context ‘ユーザーAがログインしているとき’ do
before do
# ユーザーAでログインする
end
it ‘ユーザーAが作成したタスクが表示される’ do
# 作成済みのタスクの名称が画面上に表示されていることを確認
end 
end
end
end


このようにcreateメソッドに引数を渡すことで、userオブジェクトに値を付与することができます。


【作成者がユーザーAであるタスクを作成しておく】


:taskファクトリを使ってタスクのデータを作成し、userとの関連を指定します。


■spec/system/tasks_spec.rb


require ‘rails_helper’
describe ‘タスク管理画面一覧’, type: :system do
describe ‘一覧表示機能’ do
before do
user_a = FactoryBot.create(:user, name: ‘ユーザーA’, email: ‘a@example.com’)
FactoryBot.create(:task, name: ‘最初のタスク’, user: user_a)
end
context ‘ユーザーAがログインしているとき’ do
before do
# ユーザーAでログインする
end
it ‘ユーザーAが作成したタスクが表示される’ do
# 作成済みのタスクの名称が画面上に表示されていることを確認
end 
end
end
end


わかりやすいようにname:に「最初のタスク」という値を、userの部分に「user_a」という情報を関連付けています。

【ユーザーAでログインする】


一口にログインするといっても作業を細分化していくと下記のような動作を行っていることがわかります。


①ログイン画面にアクセスする
②メールアドレスを入力する
③パスワードを入力する
④「ログインする」ボタンを押す


①ログイン画面にアクセスする

特定のURLでアクセスするときはvisit[URL]という書き方で表現します。

visit login_path


②メールアドレスを入力する
テキストフィールドに値を入れるには、fill_inというメソッドを利用します。


fill_in ‘メールアドレス’, with: ‘a@example.com


③パスワードを入力する


fill_in ‘パスワード’, with: ‘password’


④「ログインする」ボタンを押す

ボタンを押すには、click_buttonメソッドを使用します。


click_button ‘ログインする’

①~④を記述すると全体のコードは下記のようになります。

■spec/system/tasks_spec.rb


require ‘rails_helper’
describe ‘タスク管理画面一覧’, type: :system do
describe ‘一覧表示機能’ do
before do
user_a = FactoryBot.create(:user, name: ‘ユーザーA’, email: ‘a@example.com’)
FactoryBot.create(:task, name: ‘最初のタスク’, user: user_a)
end
context ‘ユーザーAがログインしているとき’ do
before do
    visit login_path
fill_in ‘メールアドレス’, with: ‘a@example.com’
    fill_in ‘パスワード’, with: ‘password’
    click_button ‘ログインする’
end
it ‘ユーザーAが作成したタスクが表示される’ do
# 作成済みのタスクの名称が画面上に表示されていることを確認
end 
end
end
end


【作成済みのタスクの名称が画面上に表示されていることを確認】


前提条件は全て整ったので、ようやく具体的な処理であるitの内容に取り掛かれます。
itの中身は、画面内に特定の内容が存在するかを検査することにします。


■spec/system/tasks_spec.rb

require ‘rails_helper’
describe ‘タスク管理画面一覧’, type: :system do
describe ‘一覧表示機能’ do
before do
user_a = FactoryBot.create(:user, name: ‘ユーザーA’, email: ‘a@example.com’)
FactoryBot.create(:task, name: ‘最初のタスク’, user: user_a)
end
context ‘ユーザーAがログインしているとき’ do
before do
    visit login_path
fill_in ‘メールアドレス’, with: ‘a@example.com’
    fill_in ‘パスワード’, with: ‘password’
    click_button ‘ログインする’
end
it ‘ユーザーAが作成したタスクが表示される’ do
expect(page).to have_content ‘最初のタスク’
end 
end
end
end


expect(page).to have_content ‘最初のタスク’という記述について、直訳すると、「page(画面)に期待します。’最初のタスク’という内容があるはずだよね」という感じです。


have_contentの部分は「マッチャ」と呼ばれていて「=」の意味を果たします。

これでテストコードは完成です。

実際にrspecコマンドにSpecファイルの場所を指定して実行します。

$ bundle exec rspec spec/system/tasks_spec.rb

実行すると、「1 example, 0 failures」と表示され、問題なくテストが通ったことを意味します。

【他のユーザーが作成したタスクが表示されないことの確認】

次はユーザーBがログインしたときに、ユーザーAのタスクが表示されないことの確認を行っていきます。ステップは下記の通りです。


①ユーザーAと、ユーザーAのタスクを作成する
②ユーザーBを作成する
③ユーザーBでログインする
④ユーザーAのタスクが表示されて以内ことを確認する

①については1つ前のテストと同じ内容なので、コードの流用が可能です。

①~④を書くために「ユーザーBがログインしているとき」というcontextを追記します。

■spec/system/tasks_spec.rb

require ‘rails_helper’
describe ‘タスク管理画面一覧’, type: :system do
describe ‘一覧表示機能’ do
before do
user_a = FactoryBot.create(:user, name: ‘ユーザーA’, email: ‘a@example.com’)
FactoryBot.create(:task, name: ‘最初のタスク’, user: user_a)
end
context ‘ユーザーAがログインしているとき’ do
before do
    visit login_path
fill_in ‘メールアドレス’, with: ‘a@example.com’
    fill_in ‘パスワード’, with: ‘password’
    click_button ‘ログインする’
end
context ‘ユーザーBがログインしているとき’ do
before do
# ユーザーBを作成しておく
    # ユーザーBでログインする
end
it ‘ユーザーAが作成したタスクが表示されない’ do
# ユーザーAが作成したタスクの名称が画面上に表示されていないことを確認
end 
end
end
end

このように1つのdescribeの中にcontextは複数記述することができます。
また、contextで囲われていない冒頭のbeforeの内容についてはcontextの内容が呼び出される前に実行されるので、ユーザーAは必ず生成されることになります。

ここでユーザーBを作成し、ログインまで実行します。

■spec/system/tasks_spec.rb


require ‘rails_helper’
describe ‘タスク管理画面一覧’, type: :system do
describe ‘一覧表示機能’ do
before do
user_a = FactoryBot.create(:user, name: ‘ユーザーA’, email: ‘a@example.com’)
FactoryBot.create(:task, name: ‘最初のタスク’, user: user_a)
end
context ‘ユーザーAがログインしているとき’ do
before do
    visit login_path
fill_in ‘メールアドレス’, with: ‘a@example.com’
    fill_in ‘パスワード’, with: ‘password’
    click_button ‘ログインする’
end
context ‘ユーザーBがログインしているとき’ do
before do
FactoryBot.create(:user, name: ‘ユーザーB’, email: ‘b@example.com’)
    visit login_path
fill_in ‘メールアドレス’, with: ‘b@example.com’
    fill_in ‘パスワード’, with: ‘password’
    click_button ‘ログインする’
end
it ‘ユーザーAが作成したタスクが表示されない’ do
# ユーザーAが作成したタスクの名称が画面上に表示されていないことを確認
end 
end
end
end


次はitの内容「ユーザーAが作成したタスクの名称が画面上に表示されていないことを確認」を記述します。

「されていない(期待しない)」場合には、「have_no_content」を使用します。

■spec/system/tasks_spec.rb

require ‘rails_helper’
describe ‘タスク管理画面一覧’, type: :system do
describe ‘一覧表示機能’ do
before do
user_a = FactoryBot.create(:user, name: ‘ユーザーA’, email: ‘a@example.com’)
FactoryBot.create(:task, name: ‘最初のタスク’, user: user_a)
end
context ‘ユーザーAがログインしているとき’ do
before do
    visit login_path
fill_in ‘メールアドレス’, with: ‘a@example.com’
    fill_in ‘パスワード’, with: ‘password’
    click_button ‘ログインする’
end
context ‘ユーザーBがログインしているとき’ do
before do
FactoryBot.create(:user, name: ‘ユーザーB’, email: ‘b@example.com’)
    visit login_path
fill_in ‘メールアドレス’, with: ‘b@example.com’
    fill_in ‘パスワード’, with: ‘password’
    click_button ‘ログインする’
end
it ‘ユーザーAが作成したタスクが表示されない’ do
expect(page).to have_no_content ‘最初のタスク’
end 
end
end
end


実行します

$bundle exec rspec spec/system/tasks_spec.rb

最終行に「2 examples 0 failares」と表示されればOKです。

【beforeを利用した共通化】

「ユーザーAがログインしているとき」と「ユーザーBがログインしているとき」の2つのcontentの内容はほぼ一緒の内容です。

■ユーザーAがログインしているとき

before do
    visit login_path
fill_in ‘メールアドレス’, with: ‘a@example.com’
    fill_in ‘パスワード’, with: ‘password’
    click_button ‘ログインする’
end

■ユーザーBがログインしているとき

before do
FactoryBot.create(:user, name: ‘ユーザーB’, email: ‘b@example.com’)
    visit login_path
fill_in ‘メールアドレス’, with: ‘b@example.com’
    fill_in ‘パスワード’, with: ‘password’
    click_button ‘ログインする’
end

このように重複が生じているコードはできればまとめて共通化したいです。


Specでは同じ階層にある全てのdescribe/content内で共通する処理については、describe/contentの1つ上の階層のbeforeの中に処理をまとめて書くことで、共通化ができます。

まずは、「ユーザーAがログインしているとき」という処理を1つ上の階層のbeforeに移植し、「ユーザーBがログインしているとき」というcontentのbeforeで行っているログイン処理を取り除きます。

■spec/system/tasks_spec.rb

require ‘rails_helper’
describe ‘タスク管理画面一覧’, type: :system do
describe ‘一覧表示機能’ do
before do
user_a = FactoryBot.create(:user, name: ‘ユーザーA’, email: ‘a@example.com’)
FactoryBot.create(:task, name: ‘最初のタスク’, user: user_a)
   visit login_path
fill_in ‘メールアドレス’, with: ‘a@example.com’
  fill_in ‘パスワード’, with: ‘password’
   click_button ‘ログインする’
end
context ‘ユーザーAがログインしているとき’ do
   it ‘ユーザーAが作成したタスクが表示される’ do 
expect(page).to have_content: ‘最初のタスク’
end
end
context ‘ユーザーBがログインしているとき’ do
before do
FactoryBot.create(:user, name: ‘ユーザーB’, email: ‘b@example.com’)
end
it ‘ユーザーAが作成したタスクが表示されない’ do
expect(page).to have_no_content ‘最初のタスク’
end 
end
end
end


これでテストを実行してもエラーが発生します。
理由は、ユーザーAでログインしているのに、ユーザーでログインしようとしたからです。
これを解決するための方法が「let」です。


【letを利用した共通化】

letは、before処理内で変数のような役割を果たします。
let(定義名) { 定義の内容 }
実際にletを使った呼び出し方を使ってみます。


■spec/system/tasks_spec.rb


require ‘rails_helper’
describe ‘タスク管理画面一覧’, type: :system do
describe ‘一覧表示機能’ do
let(user_a) { FactoryBot.create(:user, name: ‘ユーザーA’, email: ‘a@example.com’) }
let(user_b) { FactoryBot.create(:user, name: ‘ユーザーB’, email: ‘b@example.com’) }
before do
FactoryBot.create(:task, name: ‘最初のタスク’, user: user_a)
   visit login_path
fill_in ‘メールアドレス’, with: login_user.email
   fill_in ‘パスワード’, with: login_user.password
   click_button ‘ログインする’
end
context ‘ユーザーAがログインしているとき’ do
let(:login_user) { user_a }
   it ‘ユーザーAが作成したタスクが表示される’ do 
expect(page).to have_content: ‘最初のタスク’
end
end
context ‘ユーザーBがログインしているとき’ do
let(:login_user) { user_b }
it ‘ユーザーAが作成したタスクが表示されない’ do
expect(page).to have_no_content ‘最初のタスク’
end 
end
end
end


実行してみます

$bundle exec rspec epec/system/tasks_spec.rb

2 examples, 0 failares


【詳細表示機能のSpecを追加する】

■spec/system/tasks_spec.rb

require ‘rails_helper’
describe ‘タスク管理機能’, type: :system do
 let(:user_a) { FactoryBot.create(:user, name: ‘ユーザーA’, email: ‘a@example.com’) } 
 let(:user_b) { FactoryBot.create(:user, name: ‘ユーザーB’, email: ‘b@example.com’) }
 let(:task_a) { FactoryBot.create(:task, name: ‘最初のタスク’, user: user_a) }
 before do
   visit login_path
   fill_in ‘メールアドレス’,with: login_user.email
   fill_in ‘パスワード’, with: login_user.password
   click_button ‘ログインする’
 end
 describe’一覧表示機能’ do
   context ‘ユーザーAがログインしているとき’ do
     let(:login_user) { user_a }
     it ‘ユーザーAが作成したタスクが表示される’ do
       expect(page).to have_content ‘最初のタスク’
     end
   end
   content ‘ユーザーBがログインしているとき’ do
     let(:login_user) { user_b }
     it ‘ユーザーAが作成したタスクが表示されない’
        expect(page).to have_no_content ‘最初のタスク’
     end
   end
 end
 describe ‘詳細表示機能’ do
   context ‘ユーザーAがログインしているとき’ do
     let(:login_user) { user_a }
     before do
       visit task_path(task_a)
     end
     it ‘ユーザーAが作成したタスクが表示される’ do
       expect(page).to have_content ‘最初のタスク’
     end
   end
 end
end

【shared_examplesを利用する】

it ‘ユーザーAが作成したタスクが表示される’do
 expect(page).to have_content ‘最初のタスク’
end

現状、上記のitの内容について、まったく同じコードが登場しています。

これを共通化する手立てとして、「shared_examples」を作ります。
この機能をつかうと、期待する挙動をテストケース間でシェアすることができます。

shared_examples_for‘ユーザーAが作成したタスクが表示される’do
 it{ expect(page).to have_content ‘最初のタスク’}
end

この共通化した部分を使用するときは下記のように記述します。

it_behaves_like ‘ユーザーAが作成したタスクが表示される’

これを用いて全体を書き換えるとこのようになります。

■spec/system/tasks_spec.rb

require ‘rails_helper’
describe ‘タスク管理機能’, type: :system do
 let(:user_a) { FactoryBot.create(:user, name: ‘ユーザーA’, email: ‘a@example.com’) } 
 let(:user_b) { FactoryBot.create(:user, name: ‘ユーザーB’, email: ‘b@example.com’) }
 let(:task_a) { FactoryBot.create(:task, name: ‘最初のタスク’, user: user_a) }
 before do
   visit login_path
   fill_in ‘メールアドレス’,with: login_user.email
   fill_in ‘パスワード’, with: login_user.password
   click_button ‘ログインする’
 end
 shared_examples_for‘ユーザーAが作成したタスクが表示される’do
 it{ expect(page).to have_content ‘最初のタスク’}
end

 describe’一覧表示機能’ do
   context ‘ユーザーAがログインしているとき’ do
     let(:login_user) { user_a }
     it_behaves_like ‘ユーザーAが作成したタスクが表示される’
   end
   content ‘ユーザーBがログインしているとき’ do
     let(:login_user) { user_b }
     it ‘ユーザーAが作成したタスクが表示されない’
        expect(page).to have_no_content ‘最初のタスク’
     end
   end
 end
 describe ‘詳細表示機能’ do
   context ‘ユーザーAがログインしているとき’ do
     let(:login_user) { user_a }
     before do
       visit task_path(task_a)
     end
     it_behaves_like ‘ユーザーAが作成したタスクが表示される’
   end
 end
end


テストを実行すれば問題なく通ります。

$ bundle exec rspec spec/system/tasks_spec.rb

3 examples, 0 failares

【新規作成機能のSystem Spec】

タスクの名称を入力しないと登録できないようにvalidatesをかけているので、「タスクの名称を入力すると登録ができること」と「タスクの名称を入力しないと検証エラーになること」のテストケースを記述します。

■spec/system/tasks_spec.rb

require ‘rails_helper’
describe ‘タスク管理機能’, type: :system do
…
 describe ‘詳細表示機能’ doend
…
 describe ‘新規作成機能’do
   let(:login_user) { user_a }
   before do
     visit new_task_path
     fill_in ‘名称’, with:task_name
     click_button ‘登録する’
   end
   context ‘新規作成画面で名前を入力したとき’do
     let(:task_name){ ‘新規作成のテストを書く’ }
     it ‘正常に登録される’do
       expect(page).to have_selector ‘alert-success’, text: ‘新規作成のテストを書く’
     end
   end
   context ‘新規作成画面で名前を入力しなかったとき’ do
     let(:task_name) { ‘’ }
     it ‘エラーとなる’do
       within ‘#error_explanation’ do
         expect(page).to have_content ‘名前を入力してください’
       end
     end
   end
 end
end


expect(page).to have_selector ‘alert-success’, text: ‘新規作成のテストを書く’

上記のhave_selectorについて、これはHTML内の特定の要素をセレクタ(CSSセレクタ)で指定することができます。

よって、ここでは”「新規作成のタスクを書く」を登録しました”というメッセージが画面に表示されているかどうか確認しています。


within ‘#error_explanation’ do
 expect(page).to have_content ‘名称を入力してください’
end

withinのブロック内でpageの内容を検査することで、探索する範囲を画面内の特定の範囲に収めることができます。

#error_explanationというセレクタの中で、「名称を入力してください」というエラーメッセージが含まれているかどうかを調べていることになります。


$ bundle exec rspec spec/system/tasks_spec.rb

5 examples, 0 failares

【所感】

Rspecについてはぶっちゃけ相当苦手意識があったので、はじめの一歩を踏み出すのが辛かったですが、なんとか完走できました。

実際に書き始めると、ほぼ英文のようイメージで割りとスイスイいけたように思えます。

多分、変数の定義だとか、難しいメソッドがでてこなかったのでプログラミングちっくな感じがあまり出ていなかったことに要因がありそうです。

本当はもっとたくさんのメソッドや記法もありますが、未知のメソッドは必要なときになったらまた調べていこうと思います。

この記事が気に入ったらサポートをしてみませんか?