作業ログ 機能実装その2 2019/09/07

※この記事に登場するソースコードは僕個人が開発しているプロジェクトのもので仕事とは無関係です

ざっくり説明

kenta-s.hatenadiary.jp

この記事の続きです。

サービスクラスができたので今回はコントローラーを作っていきます。

POST /api/v1/folder_transfer で別のユーザーにフォルダを送信できるようにします

実装していく

まずはテスト。例によってインターフェースだけ確認できる簡単なテストを書きます。

require 'test_helper'

class Api::V1::FolderTransferControllerTest < ActionDispatch::IntegrationTest
  setup do
    @sender = users(:kentas)
    @recipient1 = users(:some_user1)

    sign_in(@sender)

    @folder = @sender.folders.create(name: 'folder')
  end

  test "create action should send a folder to recipient" do
    folder_transfer_params = {
      folder_transfer: {
        folder_id: @folder.id,
        recipient_usernames_or_emails: ['some_user1'],
      }
    }
    post api_v1_folder_transfer_index_url, params: folder_transfer_params, xhr: true
    assert_response 201
  end

end

routeを定義していないので当然失敗します

# Running:

E

Error:
Api::V1::FolderTransferControllerTest#test_create_action_should_send_a_folder_to_recipient:
NameError: undefined local variable or method `api_v1_folder_transfer_index_url' for #<Api::V1::FolderTransferControllerTest:0x00007fffc14c7098>
    test/controllers/api/v1/folder_transfer_controller_test.rb:23:in `block in <class:FolderTransferControllerTest>'


rails test test/controllers/api/v1/folder_transfer_controller_test.rb:16

route追加

  namespace :api, { format: 'json' } do
    namespace :v1 do
      resources :folder_transfer, only: [:create]
    end
  end

Controller作成

class Api::V1::FolderTransferController < ApplicationController
  before_action :authenticate_user!
  def create
    render json: {}, status: 201
  end
end

とりあえず先ほどのテストはパスするようになります

Run options: --seed 62470

# Running:

.

Finished in 0.575040s, 1.7390 runs/s, 1.7390 assertions/s.

アサーションを追加します

こんな感じにしてみました。(我ながらこのassert_differenceもっとどうにかなるだろ、、)

  test "create action should send a folder to recipient" do
    folder_transfer_params = {
      folder_transfer: {
        folder_id: @folder.id,
        recipient_usernames_or_emails: ['some_user1'],
      }
    }
    assert_difference '@recipient1.folders.count', 1 do
      assert_difference '@recipient1.folders.first.try(:images).try(:count).to_i', 3 do
        post api_v1_folder_transfer_index_url, params: folder_transfer_params, xhr: true
        assert_response 201

        json = JSON(response.body)
        assert_equal(["some_user1に3個の画像を送信しました"], json["messages"])
      end
    end
  end

走らせると当然失敗します

Run options: --seed 35602

# Running:

F

Failure:
Api::V1::FolderTransferControllerTest#test_create_action_should_send_a_folder_to_recipient [/home/kenta-s/Repositories/oak/test/controllers/api/v1/folder_transfer_controller_test.rb:29]:
Expected: ["some_user1に3個の画像を送信しました"]
  Actual: nil


rails test test/controllers/api/v1/folder_transfer_controller_test.rb:22

テストが通るようにコントローラーを実装していきます。ガーっと書きました

class Api::V1::FolderTransferController < ApplicationController
  before_action :authenticate_user!

  def create
    service = FolderTransferService.new(
      sender: current_user,
      folder: current_user.folders.find(folder_transfer_params[:folder_id]),
      recipient_usernames_or_emails:  folder_transfer_params[:recipient_usernames_or_emails],
    )
    if service.call
      render json: {messages: service.messages}, status: 201
    else
      render json: {}, status: 422
    end
  end

  private

  def folder_transfer_params
    params.require(:folder_transfer).permit(:folder_id, recipient_usernames_or_emails: [])
  end
end

適当に書いたので落ちるかと思ったんですが一発で通ってしまいました。

Run options: --seed 59691

# Running:

.

Finished in 0.667398s, 1.4984 runs/s, 5.9934 assertions/s.
1 runs, 4 assertions, 0 failures, 0 errors, 0 skips

不安なので異常系のテストも書いておきます

  test "create action should not send a folder when invalid username is given" do
    folder_transfer_params = {
      folder_transfer: {
        folder_id: @folder.id,
        recipient_usernames_or_emails: ['non_existing_user'],
      }
    }
    assert_no_difference 'Folder.count' do
      assert_no_difference 'Image.count' do
        post api_v1_folder_transfer_index_url, params: folder_transfer_params, xhr: true
        assert_response 201 # 複数のユーザーのうち、一人だけ失敗するようなことがあるのでステータスコードは常に201を返します

        json = JSON(response.body)
        assert_equal(["ユーザーが見つかりませんでした: non_existing_user"], json["error_messages"])
      end
    end
  end

error_messagesを返すように書いていないので失敗します

Run options: --seed 25534

# Running:

F

Failure:
Api::V1::FolderTransferControllerTest#test_create_action_should_not_send_a_folder_invalid_username_is_given [/home/kenta-s/Repositories/oak/test/controllers/api/v1/folder_transfer_controller_test.rb:47]:
--- expected
+++ actual
@@ -1 +1 @@
-["ユーザーが見つかりませんでした: non_existing_user"]
+nil



rails test test/controllers/api/v1/folder_transfer_controller_test.rb:40

error_messagesを返すようにします

  def create
    service = FolderTransferService.new(
      sender: current_user,
      folder: current_user.folders.find(folder_transfer_params[:folder_id]),
      recipient_usernames_or_emails:  folder_transfer_params[:recipient_usernames_or_emails],
    )
    if service.call
      render json: {messages: service.messages, error_messages: service.error_messages}, status: 201
    else
      render json: {error_messages: service.error_messages}, status: 422
    end
  end

通るようになりました

Run options: --seed 18876

# Running:

..

Finished in 0.659569s, 3.0323 runs/s, 12.1291 assertions/s.
2 runs, 8 assertions, 0 failures, 0 errors, 0 skips

コントローラーもとりあえずこれで完成とします。 全体が動くようになったらもう少しテストケースを追加します。

続きは別記事で書きます。