見出し画像

[Rspec/テストコード]今日の学習アウトプット!

テストコードとは、アプリケーションの動作確認をするために書くコード。
品質の担保のために重要な工程。

また、どんなテストが必要か把握するには、アプリの仕様への理解が必要。
逆言うと、テストコード記述は理解を深めるのを助ける。

理解を深めるにあたって、ポイントは3つ。
・細かい記法は、使用する際に調べれば良い
・それより、ここで何を確認したいのかを理解する
・挙動で気になる点があれば、処理を止めて確認する

Rubyのテストコードは、RSpecというGemを使用する。
標準でmini_testというGemが導入されているが、RSpecが主流。

テストのパターンは、
ユーザーが意図した操作を行ったときの挙動を確認する正常系と、
意図しない操作を行ったときの挙動を確認する異常系がある。

テストの種類は、
MVCなど機能ごとにチェックする単体テスト、
ユーザーが操作する一連の流れを再現して確かめる結合(統合)テストがある。

Rspec導入〜設定方法について。
まずGemflleに「gem 'rspec-rails', ~> '4.0.0'」と記述。
また、Rspecは開発&テスト環境でのみ使用するので
「group :development, :test do ~ end」内に記述する。

そしてbundle installを行う。
これでRspecを使えるような状態にした。

deviseの時と同じように、
さらにrails g rspec:installコマンドを実行して、
当該アプリケーションにRspecをインストールする。

先のコマンドで生成された「.rspec」ファイルに
「--format documentation」を記述。
これは、テストコード実行結果をターミナルに可視化する。

あり/なし、を比較するとこんな感じ↓

#--format documentationを記述した場合
user@pc_name app_name % bundle exec rspec spec/models/user_spec.rb

User
 ユーザー新規登録                    #ここから
   nicknamekが空では登録できない
   emailが空では登録できない          #ここまで、可視化されている

Finished in 0.04349 seconds (files took 3.96 seconds to load)
2 examples, 0 failures


#--format documentationを記述しない場合
user@pc_name app_name % bundle exec rspec spec/models/user_spec.rb
..

Finished in 0.01304 seconds (files took 1.12 seconds to load)
2 examples, 0 failures

これで準備は整ったので、テストファイルの作成に移る。
コマンドで作成すると、雛形が記載されたファイルが生成される。

Userモデルのテストファイルを作成するなら、
rails g rspec:model user

生成したファイルspec/models/user_spec.rbを開くと、
require 'rails_helper’と記載されている。
これはrailsの機能をテストする際に必要な設定を読み込んでいる。

ファイルが作成できたので、次は実際のテストコードの記述に進む。
describeメソッドで、「どの機能に対して」テストと行うかグループ分けする。
さらにitメソッドで、「どんな状況の」テストを行うかグループ分けをする。
itで分けたグループのことをexsampleという。

#こんな感じ
describe 'ユーザーの新規登録' do
   it 'passwordが空だと登録できない' do
     処理を記述
   end
 end

実際のテスト処理は、expectationという構文を使用する。
これは検証で得た挙動が、想定通りか確認するもの。
雛形としては、expect().to macher()

expectの引数には、検証で得た挙動を
matcherの引数には、想定した結果を記述する。

macherは、1つではなく種類がある。
例えば、includeは指定した引数が、
expectの引数に含まれているか確認するマッチャ。
eqは、指定した引数と
expectの引数が等しいことを確認するマッチャ。

次に、expectの引数は、どう書くのかという点だが、
異常系のテストでは出力されるエラーメッセージを
想定エラーメッセージと比較するのが主流。

つまり、expectには、検証を実行した結果発生したエラーメッセージを引数として渡したい。

今回は、バリデーションを確かめたいので
バリデーションエラーを起こしたい。
データ保存以外のタイミングでバリデーションを実行するには
valid?メソッドを使用する。

valid?は、エラーがあればfalseを返し、
エラーメッセージを生成する。

生成したエラーメッセージをerrorsメソッドで抽出する。
これは、インスタンスにエラー情報があると、
その内容を返すメソッド。

ただし、その抽出したエラーメッセージは複雑なので、
expectの引数には直接渡せない。

そのためfull_messagesメソッドで、
エラーメッセージを配列として取り出す。
最終的に、これと想定エラーメッセージを比較する。

コードで書くと、こんな感じ。

describe 'ユーザー新規登録' do
   it '' do
     user = User.new(パスワードだけ空のインスタンスを作成)
     user.valid?
     expect(user.errors.full_messages).to include("Password can't be blank")
   end
end

想定するエラーメッセージを、
コードで調べる方法は
binding.pryで処理をとめて
コンソールで インスタンス.error.full_messagesとすると確認できる。

作成したテストコードの実行は、
「bundle exec rspec spec/models/user_spec.rb」(Userモデルのテスト)


以下、ざっくりの流れ。

異常系のモデル単体テストの例だったが、
保存するインスタンス(データ)作成

保存できるか確認

保存できないエラーメッセージが想定するものか確認
という流れでテストした。

保存できるか確認する際のバリデーションの挙動確認については、
バリデーションを確認したいカラムが空のインスタンスを作成
(バリデーションがpresence: trueのケース)

valid?でバリデーションを実行

生じたエラーと期待するエラーとexpectationで確認
という流れ。