〜RSpec〜

〜テストを知ろう〜

テストコード

 アプリケーション内に記述する、そのアプリケーションの挙動を確認するためのコード。手動は確認項目を1つずつ手動で確認する必要があるが、テストコードはコマンド1つで全部チェックすることができる。

RSpec(アールスペック)

 Ruby on Railsのテストコードを書くために用いられるGem

正常系

 『ユーザーが開発者の意図する操作を行った時の挙動』を確認するテストコード。

異常系

 『ユーザーが開発者の意図しない操作を行った時の挙動』を確認するテストコード。

 例えば、必須項目を入力せずに送信した際は、『必須項目を入力してください』とアラート画面などがでることがある。この挙動を確認することは異常系に分類される。

単体テストコード

 モデルやコントローラーなどの機能ごとに問題がないか確かめること。例えば、PicTweetにおけるTweetモデルのテストコードでは『画像URLとテキストがない投稿は、テーブルに保存させない。』というバリデーションの挙動を確認する。

結合テストコード

 ユーザーがブラウザで操作する一連の流れを再現して、問題がないか確かめること。例えば、PicTweetにおけるツイート投稿のテストコードでは『画像URLとテキストを投稿して送信ボタンを押すと、投稿完了ページに移動し、TOPページに戻るとさきほど投稿した内容が表示されている』という流れを一気に確かめる。

 

RSpecの導入と単体テストコードを書く練習をしよう〜

テストコードの構造

【例】テストコード

RSpec.describe '簡単なテストコード' do
  describe '数字の計算' do
    it "1 + 1は2である" do
      expect(1 + 1).to eq 2
    end
  end
  describe '文字列の結合' do
    it "「カレー」と「ライス」をつなげるとカレーライスになること" do
      expect("カレー" + "ライス").to eq "カレーライス"
    end
  end
end
⑴ describe(ディスクライブ)

 日本語で、『〇〇について記述する』という意味を持つ。どのようなテストコードを書いているのかを説明するために記述する。do~endの間に記述し、入れ子構造をとることができる。

⑵ it

 『どのような結果になることを試しているのか』を記述する。 do~endの間に記述し、入れ子構造はとらない。

 example

 上記のitに記述した内容の総称のこと。

⑶ expect(X).to eq Y(エクスセプト)

 テストコードにおいて実際にコードなどを検証している部分のこと。『Xの結果はYになる』ということを確認している。このeqのように結果を判断するものを、マッチャと呼ぶ。

 マッチャ

 expectの中の記述と、結果とのつながりを表現するもの。

bundle exec(エグゼク)コマンド

 Gemの多くは、その他のGemと依存関係になっており、それらの依存関係を整理してくれるコマンド。このコマンドを使わないとエラーになることがある。

rspecコマンド

 specディレクトリ以下に書かれたRSpecのテストコードを実行するコマンド。

rails_helper

 RailsにおいてRSpecを利用する際に、共通の設定を書いておくファイル。各テスト用ファイルでこちらのファイルを読み込むことで、共通の設定やメソッドを適用する。

valid?(バリドゥ)メソッド

 日本語で「正しい」を意味し、valid?とすることで「正しいかどうか」を判定するメソッドとなる。作成したデータが正しく保存される場合は「true」を、保存されない場合はfalseを返します。また、保存されない場合は、「なぜ保存されないのか」のエラ〜メッセージも生成する。

errorsメソッド

 valid?にて判定されたデータのエラーを表示するメソッド。エラーメソッドを書くためには、続けて「full_messages」メソッドを使用する。

full_messagesメソッド

 生成されたエラーの中から、エラーメッセージを出力するためのメソッド。

include(インクルード)マッチャ

 日本語で「含む」を意味する。「expect(X).to include(Y)」の様に使用し、「Xの中にYという文字列が含まれているかどうか」を確認することができる。

  

〜効率的にテストコードを書こう〜

FactoryBot

 インスタンスをまとめることができるGem。他のファイルであらかじめ各クラスのインスタンスに定める値を設定しておき、各テストコードで使用する。

build(ビルド)

ActiveRecordのnewメソッドと同様の意味を持つ。

【例】 

 # FactoryBotを利用しない場合
user = User.new(nickname: "abe", email: "kkk@gmail.com",~)
# FactoryBotを利用する場合
user = FactoryBot.build(:user) 

before

 テストコードの同じ意図のコードをまとめることができるもの。

 require 'rails_helper'
RSpec.describe User, type: :model do
before do
# 何かしらの処理
  end

describe 'X' do
it "Y" do
# before内の処理が完了してから実行される
end
it "Z" do
# before内の処理が完了してから実行される
end
end
end

Faker(フェイカー)

 ランダムな値を生成するGem。メールアドレス、人名、パスワードなど、様々な意図に応じたランダムな値を生成してくれる。

〜PicTweetのモデルの単体テストコードを書こう〜

context(コンテキスト)

 正常系と異常系を分けるために使う記述

be_validマッチャ

 expectのインスタンスが正しく保存されることを判断する。『expect(インスタンス).to be_valid』のように使用する。

association :他のFactoryBot

 これは他のFactoryBotとアソシエーションがあることを意味している。インスタンスが生成さたと同時に、関連するFactoryBotのインスタンスも生成される。

 

〜PicTweetのコントローラーの単体テストコードを書こう〜

Request Spec

 RSpecが提供している、コントローラーのテストコードを書くために特化した手法。 

create

 テスト用のDBに値を保存するためのメソッド。ActiveRecordのcreateメソッドと同様の意味を持つ。注意点として、1回のテストが実行され、終了する毎にテスト用のDBの内容がロールバックされる。(保存された値が全て消去されてしまう。)

get

 「get 〇〇_path」のように、どこのパスにリクエストを送りたいかを記述する。「rails routes」コマンドで確かめることができる。

response

 リクエストの対するレスポンスそのものが含まれている。このレスポンスで取得できる情報に、想定する内容が含まれているかを確認することで、テストコードを書くことができる。

HTTPステータスコード

 HTTP通信において、どのような処理の結果となったのかを示すもの。

 ステータスコード      内容

   ⑴100~       処理の継続中

   ⑵200~       処理の成功

   ⑶300~       リダイレクト

   ⑷400~       クライアントのエラー

   ⑸500~       サーバーのエラー

 正常にレスポンスを得ることを確かめたい場合は、200というステータスコードを期待する。レスポンスの中からステータスコードを確かめるためには、「status」を利用する。

status

 「response.status」と実行するとこによって、そのレスポンスのステータスコードを出力できる。

body

 「response.body」と実行することによって、ブラウザに表示されるHTMLの情報を抜き出すことができる。

 

結合テストコードを書く練習をしよう〜

System Spec(システムスペック)

 結合テストコードを記述するための仕組みのこと。

Capybara(カピバラ

 System Specを記述するために必要なGem。

visit

 「viset 〇〇_path」のように記述すると、〇〇のページへ遷移することを表現できる。RequestSpecのgetと似ているが、getはあくまでリクエストを送るだけのことを意味し、visitはそのページへ実際に遷移することを意味する。

page

 現状のページを意味している。visitで訪れた先のページの見える文だけの情報が格納されている。後術するとおり、「ログアウト」などのカーソルを合わせてはじめて見ることができる文字列はpageの中に含まれない。

have_content

 「expect(page).to have_content('X')」と記述すると、visetで訪れたpageの中に、Xという文字列があるかどうかを判断するマッチャ。

fill_in

 「fill_in 'ファームの名前', with; '入力する文字列'」のように記述することで、ファームへの入力を行うことができる。フォームの名前を知るためには、検証ツールというものを使うことで知ることができる。

検証ツール

 ブラウザに標準で備わっている、HTMLの要素や、適用されているCSSのコードを確認することができる機能。

find().click

 「find("クリックしたい要素").click」と記述することで、実際にクリックできる。

change

 「expect{ "何かしらの動作" }.to change {モデル名.count }.by(1)」と記述することによって、モデルのレコードの数がいくつ変動するのかを確認できる。

 changeマッチャでモデルのカウントをする場合のみ、expect()ではなく「expect{}」となる。

 何かしらの動作の部分が「送信ボタンをクリックした時」の場合は、「find('input[name="commit"]').click」が入る。

current_path

 現在いるページのパスを示すもの。「expect(current_path).to eq 期待するページのパス」と記述すれば、今いるページが期待するページであることが確認できる。

hover

 「find("ブラウザ上の要素").hover」とすることで、特定の要素にカーソルを合わせた時に動作を再現できる。

heve_no_content

 have_contentの逆で、文字列が存在しないことを確かめるマッチャ。

 

〜ツイートの結合テストコードを書こう〜

have_selectorマッチャ

 指定したセレクタが存在するかどうかを判断するマッチャ

heve_linkマッチャ

 「expect("要素").to have_link 'ボタンの文字列', href: "リンク先のパス"」と記述することで、要素の中に当てはまるリンクがあることを確認できるマッチャ。a要素に対して用いる。

heve_no_linkマッチャ

 当てはまるリンクがないことを確認できるマッチャ。

all

 「all("クラス名")」でpageに存在する同名のクラスを持つ要素をまとめて取得できる。そして「all("クラス名")[0]」のように添字を加えることで「◯番目の指定したクラス」を取得することができる

find_link().click

 a要素で表示されているリンクをクリックするために用いる。「find_link("リンクの文字列", href: "URL").click」といった形で使う。

 

結合テストコードをまとめよう〜

サポートモジュール

 RSpecに用意されている、メソッド等をまとめる機能。

 【読み込む手順】

 ⑴ rails_helper.rbのコメントアウトを外す

 ⑵ モジュールを設定する(config.include モジュール名)