[RSpec]RSpecの基本③実際に記述してみる。
今日はRSpec基礎第3回目です。
RSpecを実際に書いてみよう!やってみた!解説
1. RSpecをインストールする
gemを使用することができるのでgemを入れる。
今回使用していくのは、
- gem 'rspec-rails'
- gem 'factory_bot_rails'
RSpecはテストの時のみ使用するので、このテストで使用するgemは group :test do
の中に記述すること。
gem fileに行けばこのように、group :test do
の中にこのような様々なgemの記述はあるから、今回は使用しないので削除してもおk!
ここに書き加えよう。
以下のように!
group :test do
# Adds support for Capybara system testing and selenium driver
#gem 'capybara', '>= 3.26'
#gem 'selenium-webdriver', '>= 4.0.0.rc1'
# Easy installation and use of web drivers to run system tests with browsers
#gem 'webdrivers'
gem 'rspec-rails'
gem 'factory_bot_rails'
end
補足:
消したgemは以下のように、defaltであるシステムテストを書くために使用されるgemです。
今回は他のを入れるので、消しても良いのです!
- capybara:
Railsアプリケーションをブラウザのようにテストできるツール。
(ブラウザで実際に起こるであろうことをシミュレートして、テストを書くことができる。)- selenium-webdriver:
Webブラウザを自動化するためのオープンソースのフレームワーク。
ブラウザで実際に起こるであろうことをシミュレートして、テストを書くことができる。- webdrivers:
上記したSeleniumとCapybaraのための自動インストールおよび自動更新機能を提供するGem。
Webドライバーを自動的にインストールして、ブラウザでテストを実行することができます。
-
bundle install
する - RSpecをアプリケーションにインストールする.
rails g rspec:install
このようにspecフォルダーが作成される!!!
補足:gem'factory_bot_rails'についてと使用方法
RSpecのテストデータを生成するライブラリで、便利なメソッドを提供してくれるgem。
使用方法について
使用方法
- gemに記入し、
bundle install
とrails g rspec:install
でインストール。 - インストールまでしたら、[spec/rails_helper.rbファイル]に以下のコードを追記していく。
# spec/rails_helper.rb
RSpec.configure do |config|
config.include FactoryBot::Syntax::Methods
end
=> これで、「factory_bot_rails」が使えるようになる。
- モデルごとに,spec/factoriesディレクトリ以下にファクトリーファイルを作成。
ex. )
- 3-1. specの下にfactoriesディレクトリを作成
- 3-2. そのfactoriesディレクトリの中にファイルを作成する
Postモデルの場合であれば、users.rb
を作成. - 3-3. ファイルの中に以下のように、デフォルトで使用する属性を定義していく。
ここからは、また以降作成方法の流れに沿って解説していきます!!!
今回はPOSTモデルについて(結合テスト)作成していきます。
2. ファイルを作成し、テストを書いていく
先ほどのコマンドでspecフォルダが作成されたので...
テストを記述するファイルをspecフォルダに作成していく。
postモデルのRSpecを作るにあたって、userも必要になるので作成していきます。
gem factory_bot_rails
の設定
2-1. まずは使用するこれを記述することによって、このgemを使用できるようになる。
# spec/rails_helper.rb
RSpec.configure do |config|
config.include FactoryBot::Syntax::Methods
end
2-2. specの下にfactoriesディレクトリを作成
2-3. そのfactoriesディレクトリの中に,テストデータ生成用のファイルを作成
- まずはpostについて作っていくためにUSERが必要なので、userを作成
- ファクトリーファイルでは、デフォルトで使用する属性を定義していく。
定型文
FactoryBot.define do
factory :モデル名 do
~属性の定義~
end
end
spec/factories/user.rb
FactoryBot.define do
factory :user do
first_name { Faker::Lorem.characters(number: 10) }
last_name { Faker::Lorem.characters(number: 10) }
first_name_kana { Faker::Lorem.characters(number: 10) }
last_name_kana { Faker::Lorem.characters(number: 10) }
email { Faker::Internet.email }
password { "password" }
password_confirmation { "password" }
after(:build) do |user|
user.image.attach(io: File.open("spec/images/no_image.png"), filename: "no_image.png", content_type: "application/xlsx")
end
end
end
-
buildメソッド:
FactoryBotで定義されたモデルオブジェクトのインスタンスを生成するメソッド。
RSpecでテストを書く際に、データベースにデータを作成することなく、モデルオブジェクトを生成するために使用される。 -
after(:build) do |user| ~ end
buildの後に実行する処理を定義するためのメソッドであり、RSpecのコールバックの一つ。
今回はこのようにafter(:build)~
の形で使用。写真がuserモデルにはActive Strageで登録するので、userが作成された後に入れると定義している!
ではこの感じでpostも作成していきます。
テーブルは以下のような感じです。
spec/factories/post.rb
FactoryBot.define do
factory :post do
post_status { 0 }
title { Faker::Lorem.characters(number: 20) }
body { Faker::Lorem.characters(number: 100) }
user
end
end
2-4. テスト用のfileを作成していく
今回テストするpostについてのfileを作成しましょう。
前回RSpecのディレクトリについて書きましたので、
トグルに一応短縮でまとめて入れておくのでわからなかったらみること!
RSpecのディレクトリについて
project/
├── app/
├── config/
├── lib/
└── spec/ *RSpecでテストコードを格納するためのディレクトリ
├── controllers/ *コントローラーに対するテストコードを置くディレクトリ
├── models/ *モデルに対するテストコードを置くディレクトリ
├── features/ *機能に対するテストコードを置くディレクトリ
├── support/ *テストコードで使用するサポートファイルを置くためのディレクトリ
│ ├── helpers/ *RSpecのテストで使用するヘルパーメソッドを定義する場所
│ └── matchers/ *独自のマッチャーを定義するための場所
└── spec_helper.rb *spec/ ディレクトリ以下のテストスイートで共通の設定を行う場所
- modelフォルダーを作成し、その中にpost_spec.rbを作成する。
ちなみに、モデルの状態としてはこのような感じです。
app/model/post.rb
class Post < ApplicationRecord
has_many :favorites, dependent: :destroy
has_many :post_comments, dependent: :destroy
belongs_to :user
#hashtag機能
has_many :post_hashtags, dependent: :destroy
has_many :hashtags, through: :post_hashtags
#ActiveStorageの設定
has_one_attached :post_image
#validation
validates :title, length: { minimum: 2 }
validates :body, length: { minimum: 2 }
#下書き、公開のenum設定
enum post_status: { published: 0, draft: 1 }
#下書き機能
def save_draft
self.post_status = :draft
save(validate: false)
end
#利用停止のuserの投稿を閲覧不可に。
scope :published, -> { where(post_status: :published) }
scope :by_active_users, -> { joins(:user).where(users: { user_status: 0 }) }
scope :visible, -> { published.by_active_users }
#いいね機能
def favorited_by?(user)
#favorites.exists?(user_id: user.id)
user.present? && favorites.exists?(user_id: user.id)
end
#検索用
def self.search_content(content, method)
if method == "perfect"
where(title: content)
elsif method == "partial"
where("title LIKE ?", "%#{content}%")
else
all
end
end
end
ではこれをテストに変換していきます。
spec/models/post_spec.rb
require "rails_helper"
RSpec.describe Post, type: :model do
subject { post.valid? }
# Factoryでデータを作る
let(:user) { create(:user) }
let(:post) { build(:post, user_id: user.id) }
it "テスト用のUserやPostが存在するか(Factoryでちゃんと作られたか確認" do
expect(user).to be_valid
expect(post).to be_valid
end
context "titleカラム" do
it "空欄でないこと" do
post.title = ""
is_expected.to eq false
end
it "2文字以上であること: 1文字は×" do
post.title = Faker::Lorem.characters(number: 1)
is_expected.to eq false
end
it "2文字以上であること: 2文字は〇" do
post.title = Faker::Lorem.characters(number: 2)
is_expected.to eq true
end
end
describe "Accociations" do
it "PostはUserが一つのみ (belongs_to test)" do
t = Post.reflect_on_association(:user)
expect(t.macro).to eq(:belongs_to)
end
it "PostはPost Commentが複数(has_many test)" do
t = Post.reflect_on_association(:post_comments)
expect(t.macro).to eq(:has_many)
end
end
describe "Instance methods" do
describe "#save_draft" do
it "saves the post as draft" do
post.update(post_status: :published)
post.save_draft
expect(post.reload.post_status).to eq("draft")
end
end
end
describe "Scopes" do
describe ".published" do
let!(:published_post) { create(:post, post_status: :published) }
let!(:draft_post) { create(:post, post_status: :draft) }
it "returns published posts" do
expect(Post.published).to eq([published_post])
end
end
describe ".by_active_users" do
let!(:active_user) { create(:user, user_status: 0) }
let!(:inactive_user) { create(:user, user_status: 1) }
let!(:active_user_post) { create(:post, user: active_user) }
let!(:inactive_user_post) { create(:post, user: inactive_user) }
it "returns posts by active users" do
expect(Post.by_active_users).to eq([active_user_post])
end
end
describe ".visible" do
let!(:visible_post) { create(:post, post_status: :published, user: create(:user, user_status: 0)) }
let!(:invisible_post1) { create(:post, post_status: :draft, user: create(:user, user_status: 0)) }
let!(:invisible_post2) { create(:post, post_status: :published, user: create(:user, user_status: 1)) }
it "returns visible posts" do
expect(Post.visible).to eq([visible_post])
end
end
end
end
3. テストの実行
- 実行コマンド:
rspec spec/テストのファイル名
今回はこのようになりますね。 rspec spec/models/post_spec.rb
何事もエラーなく成功するとこのようになります。
初めてやったときに失敗したこと
-
実行するtestmが結合テストだった場合に、関連のあるものの定義がしていないと行うことができない
と言うことを考えていなかった。
=> もとになるところから作成していこう -
作成したファイルに
require "rails_helper
が表記していなかった。
=> 以下のようなエラーでずっと進まない。笑
NameError:
uninitialized constant Post
RSpec.describe Post, type: :model do
^^^^
# ./spec/models/post.rb:1:in `<top (required)>'
No examples found.
Discussion