14
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

RailsのRSpecで行うべきテストの種類と注意点

Last updated at Posted at 2023-04-24

株式会社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の部分のことです。

spec/controllers/products_controller_spec.rb
require 'rails_helper'

describe ProductsController, type: :controller do
 # ~~~省略~~~
end

このtypeの箇所の引数を変更することで、コントローラー、モデルなどの機能ごとに使えるテストコードの中で使えるメソッドが変化します。
例えば、コントローラーで必要なテストメソッド(Matcher/マッチャーともいいます)と、モデルで必要なテストメソッドは違うものになるためです。

コントローラーのテストを実行する際に、 ProductsControllerのindexメソッドにリクエストが来た場合には、index.html.erbが表示される というテストをします。

type: :controllerでそのためのコードは以下のようなテストコードを書く形になります。

products_controller_spec.rb
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つのバリデーションのテストになります。

spec
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/requestspec/integrationspec/apiのtypeを利用して、テストを行なっていきます。
どのようなテストをメインでテストをするのかというと、APIなどで どのURLにどのようなパラメーターを投げたら、どのよなうなレスポンスを返すのか というテストをします。
APIなどの返却は結合テスト、通常のどの画面が表示されるのかなども含めたテストはシステムテストで書いてしまう方がいいとも言われています。こちらの記事が参考になります。

サンプルとする以下のコードはこちらの記事から引用したコードになります。

spec/requests/sign_up_spec.rb
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というライブラリの導入も必要になります。

spec/features/tweet_spec.rb
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の違いについて

システムスペックとリクエストスペックの使い分け

14
8
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?