39
32

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【入門】Rails APIのテスト手法まとめ

Posted at

はじめに

自分は2021年に新卒でWeb系の開発会社にフロントエンジニアとして入社し2022年で2年目になります。

実務ではReact×TypeScriptを利用したフロント周りの開発やRailsを用いたAPIの開発を行なっています。

今回は実務でRailsプロジェクトにテストを導入することになり「RSpec」について改めて学び直したのでその内容を紹介します。

はじめにRSpecの概要を説明し、その上でRails APIのCRUDの具体的なテストコードを書いていきます。

この記事の対象者

  • Railsのテストを学びたい人
  • Rails APIでのテストの書き方を知りたい人
  • RSpecに入門したい人

この記事でやらないこと

  • 環境構築
  • RSpecに関しての詳しい解説

なお本記事は、下記の記事の続きとなっています。

そのためDocker上でRailsのAPIモードの環境構築をしていない人は準備した上こちらの記事に進んでいただければと思います。

この記事の目標

  • RailsAPIでCRUDのテストを書けるようになる

RSpecとは

そもそもRSpecとは公式ドキュメントより

RSpecはRubyプログラマのためのBehaviour-Driven Developmentツールです。BDDとは
テスト駆動開発、ドメイン駆動設計、受入テスト駆動設計を組み合わせたソフトウェア開発のアプローチです。
そして受入テスト駆動計画を組み合わせたソフトウェア開発のアプローチです。RSpecはこのうち、TDDの部分を支援します。

と説明されています。

RSpecを使うことでRailsでテストを実行することができるということだけ今回は把握しておいてください。

より詳しい解説についてはRSpecの公式ドキュメントを読んでみてください。

テストを書く理由

テストを書く主な理由は、

  • 開発効率と開発体験を上げる
  • 開発製品の品質の担保
  • 画面に不具合が発生し、ユーザーの期待通りの挙動にならないことを防ぐ

また具体的にはテストを導入することで、

  • 開発中に早い段階でエラーを発見しやすくし開発コストを減らすことができる
  • 機能が増えた時に、既存の機能を壊さない可能性を上げる
  • ユーザーの操作が期待通りかをチェックできる

といった恩恵を得ることができます。

テストを書く理由についてより詳しい解説はこちらの記事がわかりやすかったのでぜひ参考にしてみてください。

テストを書く準備及びテストコードの記述

まずはじめにRailsAPIモードでのテスト書いて実行するまでの流れを解説していきます。

テストコードの記述から実行までの流れは下記の通りです

  • RSpecの導入
  • テストファイルの作成
  • テスト用のデータベースの作成
  • テストコードの実装
  • テストの実行

RSpecの導入

まずRailsテストを行うためにRSpecをインストールしていきます。

Gemfileに下記の記述を書き、docker compose buildを実行します。

Dockerfile
gem 'rspec-rails'
gem 'factory_bot_rails'

ビルドを実行

docker compose build

これでRSpecを使う準備は完了しました。

テストファイルの作成

次にテスト用のファイルを作成します。

下記のコマンドを実行しpostsをテストするためのファイルを作成します。

docker-compose run web rails g rspec:install
docker-compose run web rails g rspec:request posts_api

テスト用のデータベースを作成

次にテストで利用するためのデータベースを作成していきます。

docker-compose.ymlに下記の記述を追加します。

docker-compose.yml
  test-db:
    image: postgres
    environment:
      POSTGRES_PASSWORD: password_test
      POSTGRES_DATABASE: postgres_test
    ports:
      - "5431:5432"

ビルドとデータベースのリセット及びマイグレーションを実行

docker-compose build
docker-compose run web rails db:reset  
docker-compose run web rails db:migrate

テストコードの実装

ここからは具体的にCRUDのテストコードを書いていきます。

まずテスト用のメソットを使えるようにするためspec/spec_helper.rbに下記の一行を追加します。

spec/rails_helper.rb
RSpec.configure do |config|
  config.fixture_path = "#{::Rails.root}/spec/fixtures"
  config.include FactoryBot::Syntax::Methods # これを追加する

次にテストデータのサンプルを作成するためにspec/factories/posts.rbを作成し下記のコードを書きます。

spec/factories/posts.rb
FactoryBot.define do
  factory :post do
    title { "サンプル記事" }
  end
end

factory_botを使うことでRSpecで用いるためのテストデータの作成を簡単に行うことができます。

factory_botについてり詳しい解説はこちらを参考にしてみてください。

GETリクエストのテスト

まずはじめに投稿(Post)を全件取得するテストコードを記述します。

全件取得するコントローラー内のロジックは下記の通りです。

app/controllers/posts_controller.rb
class PostsController < ApplicationController
  before_action :set_post, only: [:show, :update, :destroy]

  # GET /posts
  def index
    @posts = Post.all
    render json: @posts
  end
end

こちらのリクエストが正しい挙動かをテストしていきます。
コードの解説はコメントにて付与しています。

spec/requests/posts_apis_spec.rb
require 'rails_helper'

describe 'GET /posts' do
  it '記事の全件取得' do
    # spec/factories/posts.rbで定義したテストデータを10件複製(配列)
    FactoryBot.create_list(:post, 10)
    # /postsのエンドポイントへGETリクエスト
    get '/posts'
    # 返り値( render json: @posts)を変数に格納
    json = JSON.parse(response.body)

    # リクエスト成功を表す200が返ってきたか確認する。
    expect(response.status).to eq(200)
    # 10件のデータが返ってきているかを確認
    expect(json.length).to eq(10)
  end
end

テストを実行

docker-compose run web bundle exec rspec spec/requests/posts_apis_spec.rb

このようになっていれば成功です。
スクリーンショット 2022-08-31 8.55.58.jpg

コントローラーの内容を変更してテストを失敗させてみます。

app/controllers/posts_controller.rb
  # GET /posts
  def index
    # 1件だけ返すように変更
    @posts = Post.first
    render json: @posts
  end

テストを実行

docker-compose run web bundle exec rspec spec/requests/posts_apis_spec.rb

テストが失敗していることが確認できます。
スクリーンショット 2022-08-31 9.03.51.jpg

GETの詳細リクエスト

次に特定の記事を取得するテストを書いてきます。

対象のコントローラーのロジックは下記です。送られてきたidの記事だけを返す処理になっています。

app/controllers/posts_controller.rb
class PostsController < ApplicationController
  before_action :set_post, only: [:show, :update, :destroy]

  # GET /posts/1
  def show
    render json: @post
  end

  private
  # Use callbacks to share common setup or constraints between actions.
  def set_post
    @post = Post.find(params[:id])
  end

  # Only allow a trusted parameter "white list" through.
  def post_params
    params.permit(:title)
  end
end

テストコードは下記です。

spec/requests/posts_apis_spec.rb
describe 'GET /posts/:id' do
  it '特定の記事を取得する' do
    # テストデータを1件作成
    post = create(:post, title: "サンプル記事")
    # /posts/#{post.id}へGETリクエスト
    get "/posts/#{post.id}"
    # 返り値を変数へ格納
    json = JSON.parse(response.body)
    # リクエスト成功を表す200が返ってきたか確認する。
    expect(response.status).to eq(200)
    # テストデータで作成した値が返ってきているかを確認
    expect(json["title"]).to eq(post["title"])
  end
end

テストを実行

docker-compose run web bundle exec rspec spec/requests/posts_apis_spec.rb

先程作成した全件取得のテストと合わせて2件のテストが成功していることが確認できます。

スクリーンショット 2022-08-31 9.11.25.jpg

POSTリクエスト

次に新規に記事を登録するPOSTリクエストをテストしていきます。

app/controllers/posts_controller.rb
  before_action :set_post, only: [:show, :update, :destroy]

  # POST /posts
  def create
    @post = Post.new(post_params)

    if @post.save
      render json: @post, status: :created, location: @post
    else
      render json: @post.errors, status: :unprocessable_entity
    end
  end

  private
    # Only allow a trusted parameter "white list" through.
    def post_params
      params.permit(:title)
    end

テストコードを書きます。

spec/requests/posts_apis_spec.rb
describe 'Post /posts' do
  # リクエストで送られてくるテストデータ
  before do
    @post_create_params = {
        title: "新規投稿"
    }
  end
  it '新しいタスクを作成する' do
    # 受け取ったテストデータをパラメタとし新規作成
    # Postデータが作成されているかをテスト(件数が1つ増えているか)
    expect { post '/posts', params: @post_create_params  }.to change(Post, :count).by(+1)
    expect(response.status).to eq(201)
  end
end

テストコード実行します。

docker-compose run web bundle exec rspec spec/requests/posts_apis_spec.rb

スクリーンショット 2022-08-31 9.31.20.jpg

PUTリクエスト

次に更新の処理が正しく動くかをテストしていきます。

app/controllers/posts_controller.rb
  before_action :set_post, only: [:show, :update, :destroy]

 # PATCH/PUT /posts/1
  def update
    if @post.update(post_params)
      render json: @post
    else
      render json: @post.errors, status: :unprocessable_entity
    end
  end
  private
    # Use callbacks to share common setup or constraints between actions.
    def set_post
      @post = Post.find(params[:id])
    end

    # Only allow a trusted parameter "white list" through.
    def post_params
      params.permit(:title)
    end

テストコードを書きます。

spec/requests/posts_apis_spec.rb
describe "PUT /posts/:id" do
  it '記事の更新' do
    # 更新対象のテストデータを作成
    post = create(:post)
    # 更新用のリクエストデータ
    @post_update_params = {
      title: "更新しました"
    }
    # PUTリクエスト
    put "/posts/#{post.id}", params: @post_update_params

    expect(response.status).to eq(200)
    # 更新後のデータとリクエストデータが一致しているかを確認
    expect(post.reload.title).to eq(@post_update_params[:title])
  end
end

テストコード実行します。

docker-compose run web bundle exec rspec spec/requests/posts_apis_spec.rb

スクリーンショット 2022-08-31 9.44.55.jpg

DELETEリクエスト

最後に削除のリクエスト処理が正しく動いているかをテストしていきます。

app/controllers/posts_controller.rb
  before_action :set_post, only: [:show, :update, :destroy]

  # DELETE /posts/1
  def destroy
    @post.destroy
  end
  private
    # Use callbacks to share common setup or constraints between actions.
    def set_post
      @post = Post.find(params[:id])
    end

    # Only allow a trusted parameter "white list" through.
    def post_params
      params.permit(:title)
    end

テストコードを書きます。

spec/requests/posts_apis_spec.rb
describe 'Delete /posts/:id' do
  it '記事をを削除する' do
    # テストデータを1件削除
    post = create(:post)
    # DLETEにリクエストを送る
    # 作成したテストデータが削除されている事を確認
    expect { delete "/posts/#{post.id}" }.to change(Post, :count).by(-1)
    # リクエスト成功を表す204が返ってきたか確認する。
    expect(response.status).to eq(204)
  end
end

テストを実行します。

docker-compose run web bundle exec rspec spec/requests/posts_apis_spec.rb

スクリーンショット 2022-08-31 9.48.39.jpg

最後に

いかがだったでしょうか。

今回はRails APIでのテストの書き方について解説をしていきました。

ぜひRailsのテスト周りについて学習をしたい人は参考にしていただけると嬉しいです。

他にも記事を出しているので合わせて読んでいただけると幸いです。

39
32
0

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
39
32

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?