Help us understand the problem. What is going on with this article?

Rails minitest 使い方(具体例あり) - API Controller 編

こんにちは。@koshi_life です。

Rails minitest 使い方(具体例あり) - Mock編
に続き、実務でRailsでAPIを1本作る機会があったので、 Controller の minitest の書き方例を備忘します。

前提

  • Ruby 2.6.0
  • Rails 5.2.2
  • DB: MongoDB v4.0.4

テスト対象モジュール

ユーザがメッセージを登録できる POST /message で受け付けるシンプルなAPIをテスト対象とします。
リクエストヘッダー x-user-token が Userテーブルに登録済みの access_token に一致しない場合はエラーにするようなAPIをテスト対象モジュールとします。

準備

アプリ作成、モジュール追加、モデル作成,コントローラー作成コマンド。

$ rails new hello-rails-api --skip-active-record --api
$ cd hello-rails-api
$ echo "gem 'mongoid'" >> Gemfile
$ bundle install --path vendor/bundle
$ rails g mongoid:config
$ rails g model user email password access_token
$ rails g model message title body
$ rails g controller message

ソース

APIはのロジックは以下の通り。

app/controllers/message_controller.rb
class MessageController < ApplicationController

  # POST /messages
  def create
    title = params['title']
    body = params['body']
    email = params['email']
    token =  request.headers['x-user-token']

    # 必須パラメータが存在しない場合は 400 返却
    if title.blank? or body.blank? or email.blank? or token.blank?
      render :status=> 400, :json => {result: 'ng', code: 'ng-001'} and return
    end

    # email が存在しない場合は 404 返却
    begin
      user = User.find_by(email: email)
    rescue
      render :status=> 404, :json => {result: 'ng', code: 'ng-002'} and return
    end

    # token が一致しない場合は 403 返却
    unless user.access_token == token
      render :status=> 403, :json => {result: 'ng', code: 'ng-003'} and return
    end

    if Message.create(title: title, body: body, user_id: user.id)
      # 保存が成功したら 201 返却
      render :status=> 201, :json => {result: 'ok', code: 'ok-001'} and return
    else
      # 保存が失敗したら 500 返却
      render :status=> 500, :json => {result: 'ng', code: 'ng-004'} and return
    end
  end

end
config/routes.rb
Rails.application.routes.draw do
  post 'message', to: 'message#create'
end
app/models/user.rb
class User
  include Mongoid::Document
  field :email, type: String
  field :password, type: String
  field :access_token, type: String
  has_many :messages
end
app/models/message.rb
class Message
  include Mongoid::Document
  field :title, type: String
  field :body, type: String
  belongs_to :user
end

テストコード

DB登録失敗以外の分岐を通るようにテストケースを書いてみました。

test/controllers/message_controller_test.rb
require 'test_helper'

class MessageControllerTest < ActionDispatch::IntegrationTest

  USERS = [
    User.new(email:'taro@example.com', password: 'pass1234', access_token:'taro-token'),
  ]

  User.collection.drop
  Message.collection.drop
  USERS.each { |user| user.save }

  URL = '/message'

  test "必須パラメーター不足 400 返却" do
    # headers: x-user-token がない
    post URL, params: { title: 'title', body: 'body-1', email: 'email-1'}, as: :json
    assert_response 400
    res = JSON.parse(response.body)
    assert_equal('ng', res['result'])
    assert_equal('ng-001', res['code'])

    # params.title がない
    post URL, headers: { 'x-user-token': 'token' }, params: { body: 'body-1', email: 'email-1'}, as: :json
    assert_response 400
    res = JSON.parse(response.body)
    assert_equal('ng', res['result'])
    assert_equal('ng-001', res['code'])

    # params.body がない
    post URL, headers: { 'x-user-token': 'token' }, params: { title: 'title', email: 'email-1'}, as: :json
    assert_response 400
    res = JSON.parse(response.body)
    assert_equal('ng', res['result'])
    assert_equal('ng-001', res['code'])

    # params.email がない
    post URL, headers: { 'x-user-token': 'token' }, params: { title: 'title', body: 'body-1', }, as: :json
    assert_response 400
    res = JSON.parse(response.body)
    assert_equal('ng', res['result'])
    assert_equal('ng-001', res['code'])

    # headers, params 全部ない
    post URL
    assert_response 400
    res = JSON.parse(response.body)
    assert_equal('ng', res['result'])
    assert_equal('ng-001', res['code'])
  end

  test "emailが存在しない 404 返却" do
    post URL, headers: { 'x-user-token': 'token' }, params: { title: 'title', body: 'body-1', email: 'ichiro@exampl.com'}, as: :json
    assert_response 404
    res = JSON.parse(response.body)
    assert_equal('ng', res['result'])
    assert_equal('ng-002', res['code'])
  end

  test "tokenが一致しない 403 返却" do
    post URL, headers: { 'x-user-token': 'xxx' }, params: { title: 'title', body: 'body-1', email: 'taro@example.com'}, as: :json
    assert_response 403
    res = JSON.parse(response.body)
    assert_equal('ng', res['result'])
    assert_equal('ng-003', res['code'])
  end

  test "登録成功 201 返却" do
    post URL, headers: { 'x-user-token': 'taro-token' }, params: { title: 'title', body: 'body-1', email: 'taro@example.com'}, as: :json
    assert_response 201
    res = JSON.parse(response.body)
    assert_equal('ok', res['result'])
    assert_equal('ok-001', res['code'])
  end

end

実行例

$ rails test test/controllers/message_controller_test.rb 
Running via Spring preloader in process 53418
Run options: --seed 59034

# Running:

....

Finished in 0.222477s, 17.9794 runs/s, 107.8763 assertions/s.
4 runs, 24 assertions, 0 failures, 0 errors, 0 skips

簡単ですが、以上です。

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away