🧘
RSpecを導入しテストカバレッジも出す!(Rails APIモード)
はじめに
今まで業務でRailsを触ってきましたが、業務都合上テスト導入まで行うことができませんでした。しかしRailsを触っていく中で、RSpecという文字を何度も目にしたため、個人開発の環境で触ってみることとしました。
導入
必要なGemを追加する
- 以下Gemを追加します
rspec-rails
-
factory_bot_rails
gemfile
group :development, :test do
~
gem 'rspec-rails'
gem 'factory_bot_rails'
~
end
- Gemfileに追加したら
bundle install
$ bundle install
テストに必要なファイルを生成
$ bundle exec rails g rspec:install
create .rspec
create spec
create spec/spec_helper.rb
create spec/rails_helper.rb****
- 試しにテストを実行する
- テストコードがないので
0 examples, 0 failures
となります
- テストコードがないので
$ bundle exec rspec
Finished in 0.00021 seconds (files took 0.06641 seconds to load)
0 examples, 0 failures
bin/rspec コマンドを作成する
- 下記により
bin/rspec
にてテスト実行できる
$ bundle binstubs rspec-core
- 実行できるか確認
$ bin/rspec spec/
Finished in 0.00021 seconds (files took 0.06641 seconds to load)
0 examples, 0 failures
- 以下のようにディレクトリ、ファイル単位でテスト実行可能
# spec/ディレクトリ配下全て実行
$ bin/rspec spec/
# spec/hoge.rbのみ実行
$ bin/rspec spec/hoge.rb
不要なファイルは作成しないようにする
- 今回、APIモードのためviewファイル用のテストファイルは必要ないため、生成しないようにします。
config/application.rb
require_relative "boot"
require "rails/all"
Bundler.require(*Rails.groups)
module Api
class Application < Rails::Application
config.load_defaults 7.0
config.api_only = true
# 追加
config.generators do |g|
g.assets false
g.helper false
g.test_framework :rspec,
fixtures: false,
view_specs: false,
helper_specs: false,
routing_specs: false
end
end
end
FactoryBot
の設定
-
FactoryBot
のメソッドを利用するために下記を設定
spec/rails_helper.rb
RSpec.configure do |config|
~
# 追加
config.include FactoryBot::Syntax::Methods
end
テストコードを書く
- 今回書くテストコードは前回書いた記事で作成したコントローラに対して書いていきます。詳しくは下記リンクからご覧ください
- 今回は
requests
ディレクトリを作成しその中にテストコードを書いていきます
FactoryBotによるテスト対象のモデルのファクトリ定義
spec/factories/location_post.rb
FactoryBot.define do
factory :location_post do
title { "サンプル投稿" }
end
end
index
spec/requests/location_posts_controller_spec.rb
require 'rails_helper'
describe 'GET /posts' do
it '全件取得' do
# spec/factories/location_posts.rbで定義したテストデータを5件作成
FactoryBot.create_list(:location_post, 5)
# エンドポイントへGETリクエスト
get 'http://localhost:3001/api/v1/location_posts'
json = JSON.parse(response.body)
# リクエスト成功を表す200が返ってきたか確認
expect(response.status).to eq(200)
# 10件のデータが返ってきているかを確認
expect(json.length).to eq(5)
end
end
- テスト実行
$ bin/rspec spec/requests
GET /location_posts
全件取得
Finished in 0.10582 seconds (files took 1.05 seconds to load)
1 example, 0 failures
show
spec/requests/location_posts_controller_spec.rb
describe 'GET /location_posts/:id' do
it '特定の投稿を取得する' do
# テストデータを1件作成
location_post = create(:location_post, title: "hokeCafe", description: "良い", address:"五反田")
# /posts/#{post.id}へGETリクエスト
get "http://localhost:3001/api/v1/location_posts/#{location_post.id}"
# 返り値を変数へ格納
json = JSON.parse(response.body)
# 200が返ってきたか確認
expect(response.status).to eq(200)
# テストデータで作成した値が返ってきているかを確認
expect(json["title"]).to eq(location_post["title"])
expect(json["description"]).to eq(location_post["description"])
expect(json["address"]).to eq(location_post["address"])
end
end
- テスト実行
$ bin/rspec spec/requests
GET /location_posts
全件取得
GET /location_posts/:id
特定の投稿を取得する
Finished in 0.1152 seconds (files took 1.05 seconds to load)
2 examples, 0 failures
Coverage report generated for RSpec to /api/coverage. 64 / 75 LOC (85.33%) covered.
create
spec/requests/location_posts_controller_spec.rb
describe 'Post /location_posts' do
# リクエストで送られてくるテストデータ
before do
@location_post_create_params = {
location_post: {
title: "hokeCafe",
description: "良い",
address:"五反田"
}
}
end
it '新しい投稿を作成する' do
# 受け取ったテストデータをパラメタとし新規作成
# Postデータが作成されているかをテスト(件数が1つ増えているか)
expect {
post 'http://localhost:3001/api/v1/location_posts',
params: @location_post_create_params
}
.to change(LocationPost, :count).by(+1)
expect(response.status).to eq(201)
end
end
- テスト実行
$ bin/rspec spec/requests
bin/rspec spec/requests
GET /location_posts
全件取得
GET /location_posts/:id
特定の投稿を取得する
Post /location_posts
新しい投稿を作成する
Finished in 0.13722 seconds (files took 1.05 seconds to load)
3 examples, 0 failures
update
spec/requests/location_posts_controller_spec.rb
describe "PUT /location_posts/:id" do
it '投稿の更新' do
# 更新対象のテストデータを作成
location_post = create(:location_post, title: "hokeCafe", description: "良い", address:"五反田")
# 更新用のリクエストデータ
@location_post_update_params = {
location_post: {
title: "hakeCafe",
description: "良い",
address:"五反田"
}
}
# PUTリクエスト
put "http://localhost:3001/api/v1/location_posts/#{location_post.id}", params: @location_post_update_params
expect(response.status).to eq(200)
# 更新後のデータとリクエストデータが一致しているかを確認
expect(location_post.reload.title).to eq(@location_post_update_params[:location_post][:title])
expect(location_post.reload.title).to eq(@location_post_update_params[:location_post][:description])
expect(location_post.reload.title).to eq(@location_post_update_params[:location_post][:address])
end
end
- テスト実行
$ bin/rspec spec/requests
GET /location_posts
全件取得
GET /location_posts/:id
特定の投稿を取得する
Post /location_posts
新しい投稿を作成する
PUT /location_posts/:id
投稿の更新
Finished in 0.15425 seconds (files took 1.08 seconds to load)
4 examples, 0 failures
destroy
spec/requests/location_posts_controller_spec.rb
describe 'Delete /posts/:id' do
it '記事をを削除する' do
# テストデータを1件削除
location_post = create(:location_post, title: "hokeCafe", description: "良い", address:"五反田")
# 作成したテストデータが削除されている事を確認
expect { delete "http://localhost:3001/api/v1/location_posts/#{location_post.id}" }.to change(LocationPost, :count).by(-1)
# リクエスト成功を表す204が返ってきたか確認する。
expect(response.status).to eq(204)
end
end
- テスト実行
$ bin/rspec spec/requests
GET /location_posts
全件取得
GET /location_posts/:id
特定の投稿を取得する
Post /location_posts
新しい投稿を作成する
PUT /location_posts/:id
投稿の更新
Delete /posts/:id
記事を削除する
Finished in 0.16811 seconds (files took 1.07 seconds to load)
5 examples, 0 failures
テストカバレッジを出す
次にテストがどのくらい成功しているかを確認するため、テストカバレッジを出す設定をしていきます。調べているとSimpleCov
なるGemを使ってテストカバレッジを出す事ができると分かったため導入します。
SimpleCov
導入
Gemfile
~
group :development, :test do
https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem
gem "debug", platforms: %i[ mri mingw x64_mingw ]
gem 'rspec-rails'
gem 'factory_bot_rails'
# 追加
gem 'simplecov', require: false, group: :test
end
~
- bundle install
$ bundle install
-
rails_helper.rb
の先頭行にSimpleCov
の設定を追加します
rails_helper.rb
# 追加
require 'simplecov'
SimpleCov.start
# This file is copied to spec/ when you run 'rails generate rspec:install'
~
前項で作成したテストを再度実行
$ bin/rspec spec/requests
bin/rspec spec/requests
GET /location_posts
全件取得
GET /location_posts/:id
特定の投稿を取得する
Post /location_posts
新しい投稿を作成する
PUT /location_posts/:id
投稿の更新
Delete /posts/:id
記事をを削除する
Finished in 0.16811 seconds (files took 1.07 seconds to load)
5 examples, 0 failures
Coverage report generated for RSpec to /api/coverage. 72 / 75 LOC (96.0%) covered.
- 最後の行に以下のような主力が追加されているかなと思います
Coverage report generated for RSpec to /api/coverage. 72 / 75 LOC (96.0%) covered.
- また
coverage
配下にindex.html
が追加されておりそちらからGUI形式で確認することも可能です
終わりに
- 読んでいただきありがとうございました。Railsを書いていたにもかかわらずRSPecに触れることができていなかったためいい勉強の機会となりました。
- 今後としてはGithubActionsに組み込んでリモートpushされた時点でテスト実行&&カバレッジ表示とかできるとより実践的かなと思いました!(できたら記事にしたい、、)
Discussion