本ページのゴール
- ruby on railsの特性についてなんとなく理解する
- ruby on railsを構成する各要素の役割とそれぞれの繋がりについて理解する
- chatGPTを利用して、より効率的に資料作成できるようになる
概要
色々あり、webアプリケーション開発をほぼしたことが無いsreチームメンバ向けに、勉強会を開くことになりました。
しかし勉強中の身で体系的にrailsについてまとめるのは辛い...
そこでchatGPTをフル活用して資料作成してやろうという考えに
railsを構成する各要素についてまとめつつ、随所にchatGPTとのやり取りを乗せていきます
目次
1 RubyとRailsの紹介
2 開発環境のセットアップ
3 railsの基本
4 データベースとの連携
5 テスト
1 RubyとRailsの紹介
rubyとrailsとはそもそも何なのか紹介しています。
1.1 Rubyとは何か
Rubyは、まつもとゆきひろ(Matz)氏によって開発されたオブジェクト指向のスクリプト言語です。簡潔で読みやすく、生産性の高いコードを書くことができます。RubyはWebアプリケーション開発や自然言語処理、テスト自動化など、様々な用途に利用されています。
1.2 Ruby on Railsとは何か
Railsは、David Heinemeier Hansson氏によって開発されたRuby用のWebアプリケーションフレームワークです。Railsは、Model-View-Controller(MVC)アーキテクチャを採用しており、開発者が高速にWebアプリケーションを構築することができます。
1.3 Ruby on Railsの特徴や用途
Railsは、以下のような特徴や用途があります。
- 高速なWebアプリケーション開発が可能
- MVCアーキテクチャを採用しており、アプリケーションの設計が容易
- ActiveRecordというORMを採用しており、データベースとのやりとりが簡単
- シンプルで美しいコードを書くことができ、生産性が高い
- 多くの拡張機能(Gem)が提供されており、柔軟な開発が可能
- スケーラビリティが高く、大規模なアプリケーションの構築にも適している
Ruby on Railsは、Webアプリケーション開発をはじめるための優れたフレームワークです。
2 開発環境のセットアップ
本筋ではないのですごくざっくり書いています。実際にセットアップする際は他の有能な記事を参考にして下さいmm
2.1 Rubyのインストール
まず、Rubyをインストールする必要があります。Rubyは、公式サイトからダウンロードすることができます。以下の手順に従ってインストールしてください。
- 公式サイト(https://www.ruby-lang.org/ja/downloads )にアクセスし、最新バージョンのRubyをダウンロードします。
- ダウンロードしたファイルをダブルクリックし、インストーラを起動します。
- インストーラの指示に従って、インストールを完了します。
2.2 Railsのインストール
次に、Railsをインストールする必要があります。RubyGemsを使ってインストールすることができます。以下の手順に従ってインストールしてください。
- コマンドプロンプトを開きます。
-
gem install rails
というコマンドを入力します。 - インストールが完了したら、
rails -v
というコマンドを入力して、バージョンが表示されることを確認します。
2.3 テキストエディタの選択と設定
最後に、開発に使用するテキストエディタを選択し、設定する必要があります。おすすめのテキストエディタとしては、Atom、VS Code、Sublime Textなどがあります。選択したテキストエディタに合わせて、必要に応じて設定を行ってください。
Ruby on Railsの開発に必要な環境は以上の3つです。しっかりとセットアップしましょう。
自分がセットアップ時に参考にした記事: 【完全版】MacでRails環境構築する手順の全て
3 railsの基本
railsを構成する各要素について説明しています。
3.1 フレームワークとは
アプリケーション開発におけるフレームワークとは、一般的に再利用可能な標準的な構造と基盤を提供する開発用のソフトウェアです。
フレームワークは、特定のプラットフォーム、プログラミング言語、またはアプリケーションの種類に合わせて設計されています。フレームワークには、データベース接続やテンプレートエンジン、セキュリティ機能、ルーティング機能、コントローラやモデルなどの標準的なコンポーネントが含まれることが多いため、開発者はこれらの機能を自分で実装する必要がなくなり、開発効率の向上が期待できます。
また、フレームワークにはコミュニティが存在しており、情報交換や質問に対する回答、さらには機能拡張のためのプラグインやGemが公開されていることがあります。
世界的に広く利用されているフレームワーク5選
- Ruby on Rails(ルビーオンレイルズ)
- Ruby言語で書かれたWebアプリケーションフレームワーク
- 簡単なコードでWebアプリケーションを開発できることが特徴
- Django(ジャンゴ)
- Python言語で書かれたWebアプリケーションフレームワーク
- 強力なORM(Object-Relational Mapping)により、簡単なコードでデータベースとのやり取りができることが特徴
- Express.js(エクスプレス)
- Node.jsで動作するWebアプリケーションフレームワーク
- 軽量で高速なことが特徴
- Laravel(ララベル)
- PHP言語で書かれたWebアプリケーションフレームワーク
- MVCアーキテクチャを採用し、簡単なコードでWebアプリケーションを開発できることが特徴
- Spring Framework(スプリングフレームワーク)
- Java言語で書かれたWebアプリケーションフレームワーク
- 豊富な機能を持ち、大規模なWebアプリケーションの開発に向いていることが特徴
3.2 プロジェクトの作成
Ruby on Railsで開発を始めるには、最初にプロジェクトを作成する必要があります。プロジェクトを作成するには、ターミナルで以下のコマンドを入力します。
$ rails new [プロジェクト名]
このコマンドを実行すると、プロジェクトのディレクトリが作成され、基本的なファイルやディレクトリが自動的に生成されます。
作成されるディレクトリ(ファイルの一覧)
- app: アプリケーションの主要な機能を含むディレクトリです。コントローラ、モデル、ビュー、ヘルパーなどが含まれます。
- bin: アプリケーションの実行可能ファイルが含まれるディレクトリです。rails、rake、bundleなどのコマンドが含まれます。
- config: アプリケーションの設定ファイルが含まれるディレクトリです。database.yml、routes.rb、application.rbなどが含まれます。
- db: データベースのマイグレーションファイルが含まれるディレクトリです。schema.rbファイルも含まれます。
- lib: アプリケーション固有の拡張機能や共有機能を含むディレクトリです。
- log: アプリケーションのログファイルが含まれるディレクトリです。
- public: 静的ファイルが含まれるディレクトリです。画像、CSS、JavaScriptなどが含まれます。
- test: テストコードが含まれるディレクトリです。test.rbやfixturesなどが含まれます。
- tmp: 一時ファイルが含まれるディレクトリです。cacheやpidsなどが含まれます。
- vendor: アプリケーションに必要な外部ライブラリが含まれるディレクトリです。
-
Gemfile: Railsアプリケーションに必要なRubyのライブラリ(gem)を定義するファイルです。このファイルには、アプリケーションに必要なgemの名前とバージョンがリストされています。
bundle install
コマンドを実行することで、Gemfileに基づいて各種モジュールをインストールできます。
3.3 MVCアーキテクチャ
Ruby on Railsは、MVCアーキテクチャに基づいて設計されています。MVCとは、Model-View-Controllerの略で、アプリケーションを3つの役割に分ける設計手法です。
- Model: データの管理、操作を行う
- View: ユーザーインターフェースを担当する
-
Controller: ユーザーの入力を受け取り、ModelとViewを連携させる
MVCアーキテクチャは、アプリケーションを複数の役割に分割することで、コードの保守性や可読性を向上させることができます。
コード例
(config/routes.rb)
Rails.application.routes.draw do
get '/index', to: 'users#index'
end
(app/controllers/users_controller.rb)
class UsersController < ApplicationController
def index
@users = User.all
end
end
(app/models/user.rb)
# app/models/user.rb
class User < ApplicationRecord
validates :name, presence: true
end
(app/views/users/index.html.erb)
<h1>Users</h1>
<table>
<thead>
<tr>
<th>Name</th>
<th>Email</th>
</tr>
</thead>
<tbody>
<% @users.each do |user| %>
<tr>
<td><%= user.name %></td>
<td><%= user.email %></td>
</tr>
<% end %>
</tbody>
</table>
3.4 ルーティング
Ruby on Railsでは、URLをコントローラーとアクションにマッピングする仕組みがあります。これをルーティングと呼びます。
ルーティングは、config/routes.rbファイルに定義されています。以下は、例として「/hello」のURLにアクセスされたときに、welcomeコントローラーのhelloアクションを呼び出すルーティングの定義です。
get '/hello', to: 'welcome#hello'
このように定義することで、ブラウザから「/hello」にアクセスすることで、welcomeコントローラーのhelloアクションが呼び出されます。
3.5 コントローラ
コントローラは、ユーザーからのリクエストを受け取り、処理を行い、ビューを呼び出す役割を担います。Ruby on Railsでは、コントローラを生成するには以下のコマンドを使用します。
$ rails generate controller [コントローラ名]
上記コマンドで作成されるファイル一覧
- app/controllers/[コントローラ名]_controller.rb: 指定されたコントローラ名に対応するコントローラファイルです。
- app/views/[コントローラ名]: 指定されたコントローラ名に対応するビューファイルが格納されるディレクトリです。
- test/controllers/[コントローラ名]_controller_test.rb: 指定されたコントローラ名に対応するテストファイルです。
- app/assets/stylesheets/[コントローラ名].scss: 指定されたコントローラ名に対応するSCSSファイルです。
- app/assets/javascripts/[コントローラ名].coffee: 指定されたコントローラ名に対応するCoffeeScriptファイルです。
例えば、下記コードではUserモデルの全量を@users変数に格納し、ビューに渡しています。
ビューとの連携部分が明記されておらず自分は初め混乱したのですが、ビューファイルの呼び出しについて
- コントローラのアクション名に対応するビューファイルを呼び出すことができる。
- (app/views/controller_name/action_name.html.erb が呼び出される)
- コントローラのアクションで render メソッドを呼び出すことで、明示的にビューファイルを指定することができる。
つまり、UsersControllerのindexアクションが呼び出されると、自動的にapp/views/users/index.html.erb というビューファイルが返される。
(app/controllers/users_controller.rb)
class UsersController < ApplicationController
def index
@users = User.all
end
end
3.6 モデル
モデルは、データの管理や操作を行う役割を担います。Ruby on Railsでは、モデルを生成するには以下のコマンドを使用します。
$ rails generate model [モデル名]
上記コマンドで作成されるファイル一覧
- db/migrate/YYYYMMDDHHMMSS_create_[モデル名].rb: データベースマイグレーションファイルです。テーブルを作成するためのスキーマを定義します。
- app/models/[モデル名].rb: モデルファイルです。ActiveRecordを用いて、テーブルと対応するモデルクラスを定義します。
- test/models/[モデル名]_test.rb: モデルのテストファイルです。Minitestを用いて、モデルの各種メソッドが期待通りに動作することを確認します。
モデルはdbと密接に関わる部分なので、詳しくは4章に記載しています。
3.7 ビュー
ビューは、コントローラが処理した結果を表示するための役割を担います。Ruby on Railsでは、ビューを生成するには以下のコマンドを使用します。
$ rails generate view [コントローラ名] [アクション名]
上記コマンドで作成されるファイル一覧
- app/views/[コントローラ名]/[アクション名].html.erb: HTMLテンプレートファイルです。ビューを表現します。
- app/views/[コントローラ名]/[アクション名].html.slim: Slimテンプレートファイルです。HTMLの記述を簡素化することができます。
- test/controllers/[コントローラ名]_controller_test.rb: コントローラのテストファイルです。Minitestを用いて、アクションの動作を確認します。
3.7.1テンプレートエンジン
Ruby on Railsでは、ビューのテンプレートエンジンとしてERB(Embedded Ruby)が標準で使用されています。ERBは、HTML内にRubyのコードを埋め込むことができるテンプレートエンジンであり、ビューの作成に広く使用されています。
ERBを使用する場合、HTMLファイルの拡張子を「.html.erb」とする必要があります。例えば、welcomeコントローラーのhelloアクションのビューを作成する場合は、「hello.html.erb」というファイル名で作成する必要があります。
erbファイルの記述例
<% @users.each do |user| %>
<li><%= user.name %></li>
<% end %>
この例では、@usersというインスタンス変数に格納されたユーザー情報を、eachメソッドを使って1つずつ取り出しています。そして、ユーザーの名前をuser.nameで取得し、
タグで囲っています。<%= %>で囲まれたコードブロックは、その中で評価された値がHTMLに埋め込まれます。4 データベースとの連携
4.1 ActiveRecord
ActiveRecordは、Ruby on RailsのMVCのMの部分であるモデル層を担当するフレームワークであり、データベースとのやりとりを簡単に行うことができます。
ActiveRecordは、データベースのテーブルとモデルクラスを1対1に対応させることができます。クラスベースのデータベーススキーマ定義をサポートしており、マイグレーション機能を使ってスキーマの変更を追跡・管理することができます。また、Active Recordには、データベーステーブルを操作するための様々なメソッドが用意されています。例えば、createメソッドを使って、新しいレコードを作成することができます。
マイグレーション機能一覧
- create_table:新しいテーブルを作成します。
- add_column:既存のテーブルに新しいカラムを追加します。
- remove_column:既存のテーブルからカラムを削除します。
- change_column:既存のカラムのデータ型やオプションを変更します。
- rename_column:既存のカラムの名前を変更します。
- add_index:既存のテーブルにインデックスを追加します。これにより、データベースの検索速度が向上します。
- remove_index:既存のテーブルからインデックスを削除します。
- add_reference:既存のテーブルに外部キーを追加します。
- remove_reference:既存のテーブルから外部キーを削除します。
- create_join_table:2つのテーブルを結合するための中間テーブルを作成します。
- drop_join_table:中間テーブルを削除します。
4.2 マイグレーション
マイグレーションは、データベースの構造を変更するための仕組みです。Railsでは、マイグレーションを使ってデータベースのスキーマを管理します。
マイグレーションは、データベースの変更を行うためのRubyスクリプトであり、db/migrateディレクトリに保存されます。マイグレーションを実行することで、データベースの構造が自動的に変更されます。
マイグレーションの具体的な流れ
例えば、usersテーブルを作成するためのマイグレーションを作成する場合は、以下のようになります。
$ rails generate migration create_users
このコマンドを実行すると、db/migrateディレクトリにYYYYMMDDHHMMSS_create_users.rbという形式のマイグレーションファイルが生成されます。
作成されたマイグレーションファイルに必要なカラム情報を追記することもできます。
class CreateUsers < ActiveRecord::Migration[6.1]
def change
create_table :users do |t|
t.string :name
t.integer :age
# usersテーブルに追加したいカラムをここに記述する
t.string :email
t.string :password_digest
t.timestamps
end
end
end
(id, created_at, updated_atというカラムは明示的に定義しなくても自動的に追加される。)
マイグレーションファイルを定義後、rails db:migrate
コマンドを実行することで、内容がdbに反映されます。
またrails db:migrate
を実行すると、マイグレーションファイルに記述された変更内容を基にdb/schema.rb
というファイルが自動的に更新されます。つまり、最新のdbの状態はdb/schema.rb
ファイルを参照すれば確認することができます。
ActiveRecord::Schema.define(version: 2023_03_23_090539) do
create_table "users", force: :cascade do |t|
t.string "name"
t.string "email"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "password_digest"
t.index ["email"], name: "index_users_on_email", unique: true
end
end
4.3 DBとモデルの紐付け
4.3.1 ApplicationRecordについて
ApplicationRecord は Rails 5 以降で導入されたクラスで、Railsのモデルクラスの親クラスとなっています。ApplicationRecord クラスには下記のような機能が実装されています。
- データベースのテーブルとの紐付け
- バリデーション
- コールバック
データベースのテーブルとの紐付け
について詳しく見ていきます。
この機能により、命名規則に従って自動的にテーブルとモデルの紐付けが行われます。具体的には、Userモデルはusersテーブルに、Postモデルはpostsテーブルに紐づけられます。
つまり4.2で出てきたusersテーブルに登録されるuser情報について、下記のようにモデルを定義することができます。
4.2のusersテーブル情報
ActiveRecord::Schema.define(version: 2023_03_23_090539) do
create_table "users", force: :cascade do |t|
t.string "name"
t.string "email"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "password_digest"
t.index ["email"], name: "index_users_on_email", unique: true
end
end
userモデルクラス
class User < ApplicationRecord
# 受け取ったメールアドレスを全て小文字に変換する
before_save { self.email = email.downcase }
# ユーザ名について文字数制限を設ける
validates(:name, presence: true, length: {maximum: 50})
# メールアドレスについてバリデーションチェックを行う
VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
validates(:email, presence: true,
length: {maximum: 255},
format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false })
(自分はApplicationRecordについての説明を読み飛ばして実装を進めたせいで、どこでDBの情報をとってきているのか理解できずかなり時間を無駄にした。)
4.3.2 実際にUserモデルを介してUsersテーブルにデータを反映してみる
$ rails console
で、アプリケーションの環境に入り対話形式でRubyコードを実行することができます
(再掲)Usersテーブル
ActiveRecord::Schema.define(version: 2023_03_23_090539) do
create_table "users", force: :cascade do |t|
t.string "name"
t.string "email"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "password_digest"
t.index ["email"], name: "index_users_on_email", unique: true
end
end
(再掲)Userモデル
class User < ApplicationRecord
before_save { self.email = email.downcase }
validates(:name, presence: true, length: {maximum: 50})
VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
validates(:email, presence: true,
length: {maximum: 255},
format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false })
has_secure_password
validates :password, presence: true, length: { minimum: 6 }
end
- User情報を登録できるか
2.7.0 :012 > hoge_user = User.create(name: 'hoge', email: 'hogea@gmail.com', password: 'hogehoge', password_confirmation: 'hogehoge')
(0.0ms) begin transaction
User Exists (0.1ms) SELECT 1 AS one FROM "users" WHERE LOWER("users"."email") = LOWER(?) LIMIT ? [["email", "hogea@gmail.com"], ["LIMIT", 1]]
User Create (0.4ms) INSERT INTO "users" ("name", "email", "created_at", "updated_at", "password_digest") VALUES (?, ?, ?, ?, ?) [["name", "hoge"], ["email", "hogea@gmail.com"], ["created_at", "2023-03-28 07:37:15.290544"], ["updated_at", "2023-03-28 07:37:15.290544"], ["password_digest", "$2a$10$.iHyjQQHUi/zN/29sydUqumXXZf3fulzQyIGi0Zy8FJJW1ZCF.nEe"]]
(5.8ms) commit transaction
作成できました。
本筋とは関係ないですが、なぜpasswordがpassword_digestとしてハッシュ化されて登録されているかはrailsチュートリアルを参照してください。
(シンプルな例を作るべきところですが、サボって既存の環境を使い回しました。ごめんなさい。)
- インデックスの制約(メールアドレスの一意制約)に反するモデルを作成しようとした場合
2.7.0 :011 > hoge_user = User.create(name: 'hoge', email: 'hoge@gmail.com', password: 'hogehoge', password_confirmation: 'hogehoge')
(0.0ms) begin transaction
User Exists (0.3ms) SELECT 1 AS one FROM "users" WHERE LOWER("users"."email") = LOWER(?) LIMIT ? [["email", "hoge@gmail.com"], ["LIMIT", 1]]
(0.1ms) rollback transaction
登録できず、rollbackされました。
- モデルで定義したバリデーションチェックに反するモデル(passwordが6文字未満)を登録しようとした場合
2.7.0 :014 > aaaaa_user = User.create(name: 'aaaaaaa', email: 'aaaaa@gmail.com', password: 'aaaa', password_confirmation: 'aaaa')
(1.3ms) begin transaction
User Exists (0.3ms) SELECT 1 AS one FROM "users" WHERE LOWER("users"."email") = LOWER(?) LIMIT ? [["email", "aaaaa@gmail.com"], ["LIMIT", 1]]
(0.1ms) rollback transaction
こちらも登録できず。
rollback時のエラーメッセージについて
一意制約に反してUser Exists
が返されるのは分かるが、バリデーションチェックで弾かれる際にもUser Exists
になるのは納得いきません。
chatGPTに聞いてみたら、Active Recordがエラーを内部でキャッチして実情と異なるメッセージを返してしまうことは有名な話らしいです。特にuniquenessバリデーションについては頻繁に返されるため、信頼性が薄いらしいです。
4.3.3 モデル同士の関連付け
(app/models配下のお話)
Railsでは、異なるテーブル同士を関連付けることができます。例えば、ユーザーが複数の投稿を持つ場合、has_manyとbelongs_toを使って、UserモデルとPostモデルを関連付けることができます。
class User < ApplicationRecord
has_many :posts
end
class Post < ApplicationRecord
belongs_to :user
end
このようにすることで、user.postsのようにして、ユーザーが持つ投稿を全て取得することができます。逆に、post.userのようにして、投稿が属するユーザーを取得することもできます。
5 テスト
5.1 テストフレームワーク
railsにはデフォルトでMinitestとRSpecの2つのテストフレームワークが用意されています。基本的にどちらか一方を採用することが多いらしいです。
5.1.1 Minitest
Railsには軽量で標準的なテストフレームワークであるMinitestが含まれています。MinitestはRuby標準のテストフレームワークであるTest::Unitの代替として作られました。以下はMinitestの主な機能や使い方の解説です。
Minitestでは、テストは通常、testディレクトリ内のファイルに書かれます。各ファイルはクラスとして定義され、テストケースはそのクラスのインスタンスメソッドとして書かれます。例えば、Userモデルのnameのバリデーションチェックに関するテストを行う場合、下記のようになります。
テスト例
# test/models/user_test.rb
require 'test_helper'
class UserTest < ActiveSupport::TestCase
test "name should be present" do
user = User.new(name: "", email: "test@example.com", password: "password")
assert_not user.valid?
end
end
テストはrails test
で実行することができます。
Minitestでは、アサーションを使ってテストの結果をチェックします。アサーションは、以下のようなものがあります。
アサーションの一覧
- ssert: 引数がtrueであることを確認する
- refute: 引数がfalseであることを確認する
- assert_equal: 2つの引数が等しいことを確認する
- assert_not_equal: 2つの引数が等しくないことを確認する
- assert_nil: 引数がnilであることを確認する
- assert_not_nil: 引数がnilでないことを確認する
5.1.2 RSpec
RSpecは、Rubyプログラミング言語のBDD(行動駆動開発)フレームワークで、Railsのテストフレームワークの一つです。RSpecを使用することで、アプリケーションの動作を詳細に定義し、それをテストすることができます。RSpecは、Railsアプリケーションのコントローラ、モデル、ビュー、ルーティング、ヘルパーメソッドなど、さまざまな側面をテストするための柔軟な機能を提供しています。
Minitestに比べて柔軟性が高く、読みやすさに優れています。また、RSpecは、モックやスタブなどの機能を提供しており、Railsアプリケーションの開発をより容易にするための豊富な機能を提供しています。
こちらもMinitestと同様にユーザモデルのnameのバリデーションチェックに関するテストを記述すると下記のようになります。
テスト例
# spec/models/user_spec.rb
require 'rails_helper'
RSpec.describe User, type: :model do
it "name should be present" do
user = User.new(name: "", email: "test@example.com", password: "password")
expect(user).not_to be_valid
end
end
ここで、describeとitはRSpecのメソッドです。
アサーションは、以下のようなものがあります。
アサーションの一覧
- expect(actual).to eq(expected):actualとexpectedが等しいことを検証します。
- expect(actual).to be(expected):actualがexpectedと同じオブジェクトであることを検証します。
- expect(actual).to be_truthy:actualが真であることを検証します。
- expect(actual).to be_falsey:actualが偽であることを検証します。
- expect(actual).to be_nil:actualがnilであることを検証します。
- expect(collection).to include(expected):collectionにexpectedが含まれていることを検証します。
- expect(actual).to respond_to(expected):actualがexpectedというメソッドに応答することを検証します。
- expect { block }.to raise_error(expected):blockの実行中にexpectedというエラーが発生することを検証します。
- expect(actual).to match(/expression/):actualが/expression/という正規表現にマッチすることを検証します。
5.1.3 MinitestとRSpecの比較
- 構文: RSpecはDSL(Domain Specific Language)でテストを記述することができ、人間が自然な形でテストコードを記述できることが特徴です。一方、MinitestはRubyの標準的なassertion構文を使った書き方をすることができます。
- 使い方: RSpecはテスト駆動開発(TDD)や行動駆動開発(BDD)といったアジャイル開発手法においてよく用いられます。Minitestは、Railsに同梱された標準的なテストフレームワークであり、Railsの機能や挙動を確認するための単体テストを行う場合によく使われます。
- 機能: RSpecには、Minitestにはない多数の機能があります。例えば、RSpecはFactoryBotやCapybaraなどの便利なライブラリを使ってテストを書くことができます。
すごく雑にいうと、Minitestは単体テストに、RSpecは統合テストやシステムテストにおいて優位性があるようです。
5.2 テストの種類
railsにおけるテストは、主に単体テスト(モデルテスト)、機能テスト(コントローラテスト)、統合テスト(システムテスト)の3つがあります。
5.2.1 単体テスト(モデルテスト)
単体テストとは、モデルのバリデーションやメソッドの振る舞いを確認するテストです。例えば、データベースに保存される前にモデルが有効であるかどうかを検証するために、モデルに定義されたバリデーションをテストすることができます。単体テストは、アプリケーションの中で最も単純であるため、最初に実装されることが多く、より細かい単位でテストを実行することができます。
5.1で書いたテストは全て単体テストにあたります。
ですので実装例は省略します。
5.2.2 機能テスト(コントローラテスト)
機能テストとは、コントローラーのアクションやビューの表示など、機能全体のテストです。例えば、ユーザーがログインしたときに、正しいページにリダイレクトされるかどうかを検証することができます。機能テストは、単体テストよりも大きな範囲をカバーすることができますが、アプリケーション全体をテストするわけではないため、統合テストが必要な場合もあります。
3.5に記載している通り、$ rails generate controller [コントローラ名]
を実行すると自動的にコントローラのテストファイルも生成されます。
UsersControllerのindexアクションが HTTP 200 ステータスコードを返すかどうかを確認するテストの実装例を記載しておきます。
テスト実装例(RSpec)
# test/controllers/users_controller_test.rb
require 'test_helper'
class UsersControllerTest < ActionController::TestCase
test "should get index" do
get :index
assert_response :success
end
end
ActionController::TestCaseクラスはRailsアプリケーションのapp/controllersディレクトリ内に定義されたコントローラークラスを自動的にインポートします。これにより、自動的にUsersControllerがインポートされています。
5.2.3 統合テスト(システムテスト)
統合テストとは、実際のアプリケーションと同じ環境でテストを実行し、全体的な動作を確認するテストです。例えば、ユーザーがログインしてから、新しい記事を投稿し、それを表示するまでの一連の動作を検証することができます。統合テストは、アプリケーション全体をテストするため、より高いレベルのテストとなります。
まず、
rails generate system_test <test_name>
を実行し、test/system/
配下にテストファイルを生成します。そして、そこにシステムテストを実装していきます。
テスト実装例(RSpec)
require "application_system_test_case"
class UsersTest < ApplicationSystemTestCase
test "visiting the index" do
visit users_url
assert_selector "h1", text: "Users"
end
test "creating a User" do
visit users_url
click_on "New User"
fill_in "Name", with: "Test User"
fill_in "Email", with: "test@example.com"
fill_in "Password", with: "password"
fill_in "Password confirmation", with: "password"
click_on "Create User"
assert_text "User was successfully created"
assert_selector "h1", text: "Users"
end
end
-
test "visiting the index"では、visitメソッドでusers_urlにアクセスし、assert_selectorメソッドで"Users"というテキストが存在するかどうかを検証しています。
-
test "creating a User"では、visitメソッドでusers_urlにアクセスし、"New User"というテキストが表示されているリンクをクリックして、フォームに値を入力して送信するという操作を行い、最後に作成されたユーザーが一覧に表示されていることを検証しています。
システムテストを実行するためには
rails test:system
コマンドを実行します。
感想
- 自力で書くよりも圧倒的に短い工数で書き上げることができた
- ざっくり8時間くらいで書き上げることができた
- 外部サイトを使うことなく、ほぼchatGPTだけで完結したので楽だった
- 初段の返信だけでは説明が不十分なことがあった
- だが、何回かラリーすることで十分な内容までもって行けた
- 資料作成と学習を同時にできたのは期待通り
- ラリーを繰り返すことで分からないことが全て解決するのですごく楽しい
- たまに嘘ついて来るので注意が必要
- オープンクエスチョンすると、細部で間違っていることがあった
- 気になったらより前提条件を明示して質問し直すことが必要