自転車とプログラミング

元自転車メーカーのマーケター、今は自社開発企業に勤めるエンジニアが主にプログラミングの話を書きます。

「Everyday Rails - RSpecによるRailsテスト入門」でRSpecを学ぶ 導入〜モデルスペック

こんにちは、watanabeです。 RSpecの学習を始めてまいりました。

今回はRailsプロジェクトへのRSpecの導入と、モデルスペックについて学びました。

Rspecの導入

rspec-rails gemのインストール

Railsプロジェクトのテスト環境と開発環境にRSpecを追加します。 Gemfilegem 'rspec-rails'と記述します。

rspec-rails gemは学習した時点ではver6.1.2が最新で、Rails7シリーズに対応しています。

github.com

RSpecのインストール

RSpecをプロジェクトにインストールします。

$ bundle install
$ rails g rspec:install

また、インストール状態ではRSpecを起動させる際に$ bundle exec rspec ...と記述する必要があります。 これは以下のオプションでbin/rspecもしくはrspecに短縮できます

$ bundle binstubs rspec-core

DBの設定

新たなプロジェクトにRSpecを導入した場合、DBの設定が必要です。 config/database.ymlを確認して適宜初期状態から変更します。

設定ファイルを修正したら、以下のコマンドでDBを作成します。

$ bin/rails db:create:all

追加設定

RSpecをインストールすると $ bin/rails generate... でspecが生成されるようになる。 何が生成されるかはconfig/application.rbで設定可能。

module Projects
    class Application < Rails::Application
        config.load_defaults 7.1
        config.autoload_lib(ignore: %w(assets tasks))
        
        config.generators do |g|
            g.test_framework :rspec,
                fixtures: false, view_specs: false, helper_specs: false, routing_specs: false
        end
    end
end

また、.rspecRSpecの設定ファイルになっており、テスト結果の出力形式などを設定できる。 一例としてドキュメント形式でのテスト結果出力設定が挙げられていた。

# .rspec
--format documentation

minitest → RSpecへの移行

既存のminitestはそのままにRSpecのファイルを追加していく。 minitestのテストが移し終わったらminitestを削除する 個人開発はまだしも商業プロジェクトだと入れ替えの最中も開発が進行するので大変そう…👀

テンプレートに依る設定

Rails テンプレートで初期設定にRSpecを追加できる。scaffoldして自動でgemを入れたりDBをmigrationすることができる。

Rails アプリケーションのテンプレート - Railsガイド

モデルスペック

モデルはロジックの土台になるのでテストの優先度が高い。 モデルからスペックを書く。 モデル移行はリクエスト(apiやアクションのスペック)→システムスペック(システムテスト)といった流れ。

モデルスペックでやることは主に以下のチェック。

  • バリデーション
  • エラーメッセージ
  • 正常系ではないエラー条件テスト
  • インスタンスメソッド

バリデーションチェックのスペック例がこちら

# model_spec.rb
require 'rails_helper'

RSpec.describe User, type: :model do
  it "is valid with a first name, last name and email, and password" do
    user = User.new(
      first_name: "Aaron",
      last_name:  "Sumner",
      email:      "tester@example.com",
      password:   "dottle-nouveau-pavilion-tights-furze",
      )
    expect(user).to be_valid
  end
end

it "" doにテストのタイトルがつけられる。ふるまい駆動開発をサポートしているとあって、ここに記述するのはどういった挙動が望ましいか、という観点になる。この例では「諸々の属性を持っていれば検証が通る」となっている。

先で学ぶことだが、よりふるまいを分岐させていくcontextなどの文法が用意されているので、「〇〇のユーザーの場合」などシチュエーションに応じたふるまいをテストするように構築できるのはminitestにはない強みと感じる。

expect以降がチェック部分です。be_validマッチャ(minitestでいうアサーションのこと)を使用して、expect直後の実際の値に対する期待する挙動をマッチャで表現し、チェックします。このチェックを通過すればテストが通過します。

マッチャに関しては訳をされている伊藤さんの記事がわかりやすいです。

qiita.com

describe content before after

describeではクラスやシステムの機能に関するアウトラインを記述し、contextでは特定の状態に関するアウトラインを記述するようにすることでテストコードをふるまいによって区分し、可読性が高い状態を作ることができます。

before, afterはそれぞれテスト実行の前後に行う処理を記述できます。

require 'rails_helper'

RSpec.describe Note, type: :model do
    before do
        ...
    end

    after do
        ...
    end

    describe "" do
        context "" do
            it "" do
            end
        end
    end
end

beforeは複数テストで登場する処理をDRYにする目的に、afterはテスト後に不要になったデータの消去などの目的に使用されます。

教材

教材 RSpecの教材としては定番?の「Everyday Rails - RSpecによるRailsテスト入門」を使っています。 フィヨルドブートキャンプのメンター兼ソニックガーデンのエンジニアをされている伊藤淳一さんが訳をされています。 Rails7に対応修正した初心者〜中級者向けの内容となっているので信頼度が高いかなと思います。

leanpub.com