株式会社TECH LUCKという会社で代表兼エンジニアをしている齊藤です。
DXプロジェクト、開発プロジェクト、Rails開発などでお困りごとがありましたら弊社HPからご相談をいただけますと幸いです。
以下のような問題に対応することが可能です。
- プロジェクトでRailsエンジニアが足りなくて困っている
- Railsのバージョンアップをしたいがノウハウ・リソースが足りなくて困っている
- オフショア開発をしているが、要件の齟齬やコード品質が悪いので改善したい
また、Railsエンジニアも募集しておりますので、興味がありましたら弊社HPからご連絡いただけますと幸いです。
前提
Railsプロジェクトの中でRSpecでテストコードを記述する際に、Feature Spec, Sysmtem Spec, Controller Specなど多くのテストの種類があり、混乱する方も多いと思います。
この記事では、大枠としてどのようなテストコードを書いていくべきか、RSpecの諸々のSpecの違いは何かをまとめました。
注意点
この記事ではテストコードの書き方については触れませんのでご了承ください。
テストの種類
システム開発におけるテストの種類は、大きく以下の4つに分かれます。(1回1回のテストの範囲が小さい単位順に記載しています。)
テストの種類 | 別名 | テスト内容 |
---|---|---|
単体テスト | ユニットテスト/UT | 1つのクラス、関数、メソッドが正しく動作するかどうかを確認します。 |
結合テスト | 連結テスト、統合テスト、インテグレーションテスト/IT | 特定の機能が正しく動作するかどうかを確認します。投稿作成画面や投稿編集画面などの画面単位でのテストが機能テストとなります。 |
システムテスト | システムテスト/ST、エンドツーエンドテスト / E2E | ユーザーが実際に使用する一連の流れを再現しシステム正しく動作するかどうかを確認します。特定のクラス、関数、メソッドなどのコンポーネントや、投稿作成の機能という単位ではなく、システム全体のテストを指しています。機能テストとは違い、「ログインして、投稿を作成して、投稿を編集する。」という一連の流れをテストします。 |
RSpecのSpecの種類
Specとは、RSpecの以下のコードの中の type: :controller
の部分のことです。
require 'rails_helper'
describe ProductsController, type: :controller do
# ~~~省略~~~
end
このtype
の箇所の引数を変更することで、コントローラー、モデルなどの機能ごとに使えるテストコードの中で使えるメソッドが変化します。
例えば、コントローラーで必要なテストメソッド(Matcher/マッチャーともいいます)と、モデルで必要なテストメソッドは違うものになるためです。
コントローラーのテストを実行する際に、 ProductsControllerのindexメソッドにリクエストが来た場合には、index.html.erbが表示される というテストをします。
type: :controller
でそのためのコードは以下のようなテストコードを書く形になります。
expect(response).to render_template :index
上記のコードでtype: :model
を指定した場合には上記のコード自体が実行されずに落ちてしまう形になります。
RSpecには以下の種類のSpecがあります。
※全部を調べられてはいないので、他にあれば教えてください。
RSpecで作成するディレクトリ | Specの種類 | どのテストで使うか |
---|---|---|
spec/view | :views | ビューの単体テスト |
spec/models | :model | モデルの単体テスト |
spec/controllers | :controller | コントローラーの単体テスト |
spec/helpers | :helper | ヘルパーメソッドの単体テスト |
spec/routing | :routing | ルーティングの単体テスト |
spec/jobs | :job | ジョブの単体テスト |
spec/mailer | :mailer | メーラーの単体テスト |
spec/request, spec/integration, spec/api | :request | 結合テスト |
spec/feature | :feature | システムテスト |
spec/system | :system | システムテスト |
※Feature SpecとSystem Specの違いについて
Feature SpecとSystem SpecはどちらもRSpecで提供されているE2Eテストの機能です。
Feature Specのほうが歴史が長く、古いバージョンのRailsプロジェクトではよく使われています。しかし、Rails5.1で System SpecがRSpecに導入されており、現状では両方とも使うことができますが、公式のREADMEではSystem Specを推奨しているようです。Feature Specは引き続きサポートしていくとのことです。
RSpecでの書き方について
単体テスト
特定のモデルの1つのメソッド、関数ごとにテストをする形になります。
以下はUserモデルの1つのバリデーションのテストになります。
require 'rails_helper'
RSpec.describe User, type: :model do
describe '#create' do
before do
@user = FactoryBot.build(:user)
end
it "nicknameが空だと登録できない" do
@user.nickname = nil
@user.valid?
expect(@user.errors.full_messages).to include("Nickname can't be blank")
end
end
end
このような形で1つ1つのテストをする形になります。
結合テスト
spec/request
、spec/integration
、spec/api
のtypeを利用して、テストを行なっていきます。
どのようなテストをメインでテストをするのかというと、APIなどで どのURLにどのようなパラメーターを投げたら、どのよなうなレスポンスを返すのか というテストをします。
APIなどの返却は結合テスト、通常のどの画面が表示されるのかなども含めたテストはシステムテストで書いてしまう方がいいとも言われています。こちらの記事が参考になります。
サンプルとする以下のコードはこちらの記事から引用したコードになります。
RSpec.describe "Users signup", type: :request do
example "valid signup information" do
get signup_path
expect {
post users_path, params: { user: { name: "Example User",
email: "user@example.com",
password: "password",
password_confirmation: "password" } }
}.to change(User, :count).by(1)
redirect_to @user
follow_redirect!
# Test
assert_template 'users/show'
assert is_logged_in?
end
end
システムテスト
システムテストはユーザーが実際に利用する画面を操作を再現してのテストになります。
この画面に訪れて、このボタンをクリックしたら、ツイート作成画面に遷移して、必須項目を入力して作成ボタンを押すと、DBに記事が1つ作成され、投稿一覧画面が表示される というようなテストを記載します。
また、画面のテストを行うフレームワークであるCapybara
というライブラリの導入も必要になります。
describe 'ツイート作成', type: :system do
describe '通常のユーザーの場合' do
let!(:article) { create(:user) }
it 'ツイートを作成することができる' do
visit tweets_path
fill_in 'tweet[content]', with: '今日はいいことがあった!'
click_on 'ツイート新規作成'
expect(page).to have_current_path(tweets_path)
end
end
end
参考記事
テストについて
機能テストについて
RSpecについて
RSpecでの単体テストについて
RSpecのSpec typeについて
System SpecとFeature Specの違いについて
システムスペックとリクエストスペックの使い分け