課題で出てきて、初めて取り組んだRSpec!
色々なポイントを学んだので備忘録として残しておく。
初学者なので、間違ってる点などあればご指摘下さい。
バージョン
- ruby 3.2.2
- Rails 6.1.7.6
作成しているアプリはタスク管理アプリ
SystemSpecの基本
Factoryを使用したテスト
Factoryとは、railsでテストをする時用のテストデータを作成してくれるテンプレートのこと。
factory_bot_rails
というgemをインストールすることで使用できるようになる。
(Factoryを使用する手順(インストール方法など)は今回は省略。)
今回のタスク管理アプリで、「一覧画面に遷移した場合」→「作成済みのタスク一覧が表示される」というテストコードを書く際、Factoryを使用した。
FactoryBot.define do
factory :task do
name { 'パパ' }
content { '日曜日歯医者' }
end
end
まず、 spec/factories/task_spec.rb
の中に、テストデータの定義的なものを書く。
上記のように書くことで、テストデータの基本内容は、 name
が、「パパ」、 content
が「日曜日歯医者」となる。
require 'rails_helper'
RSpec.describe 'タスク管理機能', type: :system do
describe '一覧表示機能' do
context '一覧画面に遷移した場合' do
it '作成済みのタスク一覧が表示される' do
FactoryBot.create(:task)
visit tasks_path
expect(page).to have_content '日曜日歯医者'
end
end
end
end
このコードの説明。
6行目の
FactoryBot.create(:task)
の一文の中の「:task」によって、 spec/factories/task_spec.rb
の中の、2行目
factory :task do
の部分の task
が繋がり、 spec/factories/task_spec.rb
で定義した内容を元にテストデータが作成される。
この場合、 name
が、「パパ」、 content
が「日曜日歯医者」というテストデータとなる。
なので8行目の
expect(page).to have_content '日曜日歯医者'
の一文で、「日曜日歯医者」の文字がページの中に含まれているかを確認しており、このテストは成功すれば、プログラムは正しいということ。
また、以下のような書き方もある。
require 'rails_helper'
RSpec.describe 'タスク管理機能', type: :system do
describe '一覧表示機能' do
context '一覧画面に遷移した場合' do
it '作成済みのタスク一覧が表示される' do
FactoryBot.create(:task, content: '日曜日買い物')
visit tasks_path
expect(page).to have_content '日曜日買い物'
end
end
end
end
違いは6行目で
FactoryBot.create(:task, content: '日曜日買い物')
「content: '日曜日買い物'」が有るかどうか。
このように content: '日曜日買い物'
を入れることで、 spec/factories/task_spec.rb
で定義した基本のテストデータ、 name
が、「パパ」、 content
が「日曜日歯医者」というのを
name
が、「パパ」、 content
が「日曜日買い物」というテストデータに変えることができる。
「タスクを新規作成した場合、新規登録が正常に完了するか」というテストのコード
これを考える際、私は
require 'rails_helper'
RSpec.describe 'タスク管理機能', type: :system do
describe '新規作成機能' do
context 'タスクを新規作成した場合' do
it '新規登録が正常に完了する' do
FactoryBot.create(:task)
visit task_path(Task.last)
expect(page).to have_content ’投稿を作成しました!’
expect(page).to have_content '日曜日歯医者'
とすると、エラーになってしまった💦「投稿を作成しました!」なんて無いよーと言ってます。
この「’投稿を作成しました!’」というのは
def create
@task = Task.new(task_params)
if @task.save
redirect_to task_path(@task.id), notice: "投稿を作成しました!"
else
render :new
end
end
上記のように、新規タスク作成した時に、 notice
にて、投稿を作成しました、と出るようにしていたので、新規作成後の遷移したページに「投稿を作成しました!」という表示があれば、テストできるのではないかと考えたのですが、
なぜ、これではテストに失敗してしまうのかというと
このFactoryBotで作成されたテストデータによって作成されたページというのは、tasks_controller
の中の create
アクションは通過していない!!そのため、「投稿を作成しました!という文は無い!
とメンターさんに教えてもらいました!!なるほど!!確かにそうだ!!
ということで、この新規作成完了のテストは FactoryBot
は使わず
describe '新規作成機能' do
context 'タスクを新規作成した場合' do
it '作成したタスクが表示される(新規登録が正常に完了する)' do
visit new_task_path
fill_in 'task_name', with: 'パパ'
fill_in 'task_content', with: '日曜日歯医者'
click_on 'Create Task'
expect(page).to have_content '日曜日歯医者'
end
end
end
というコードに書き直し、無事課題をクリアすることができました!
ちなみに、この fill_in
を使用する際にもポイントがあり、
fill_in 'task_name', with: 'パパ'
fill_in 'task_content', with: '日曜日歯医者'
この task_name
と task_content
の部分を、
fill_in 'name', with: 'パパ'
fill_in 'content', with: '日曜日歯医者'
というように、カラム名をそのまま書きがちだが、これだとエラーになることがあるとのこと。
カラム名そのままでなく、Railsが自動で作成してくれているIDを用いて指定すると、うまくいく。
RSpecについての学びはこれで以上〜!お疲れ様でした!!
ちなみに、RSpecのこと以外でも、面白い学びがあったので、それも書き残しておく。
visit task_path(Task.last)
この、 task_path(Task.last)
の部分。
task_path
って、
task_path(task.id)
というように、後に id
を指定して、 path
の先を指定するイメージだったけど、今回は、 task_path(Task.last)
というように、 id
を指定していないのにうまくプログラムが動くのが疑問だったので、調べてみた。
まず、Railsガイドで、 last
メソッドの使い方を調べてみた。
last
とはモデルの最後のレコードを取得するメソッドである。
Railsガイドによると、 id
も含めて、最後のレコード全体を取得しているのがわかるけど、なんでこれで id
を取得できるのかが疑問だったのでメンターさんに聞いてみた。
すると、
Railsが、このデータ全体から id
のみを取得してくれる、とのこと!! Railsの機能らしい!!
おー!そうなんだ!
なので、実は、 task_path(task.id)
というのも、 task_path(task)
としてしまっても、きちんと動くのだそう!!
へぇーーー!そうだったんだ!!
初学者の私にとっては、とっても面白く、100「へぇ」くらいの学びでした!(笑)
本日は以上!お疲れ様でした!