Rails Request Specはどこまでテストする?
Controller / Query / Model の責務分離を実例で解説
RailsでAPIを実装していると、Request Specを書く機会が多いと思います。
しかし初心者の頃によくあるのが、
「Request Specでロジックまで全部テストしてしまう」
というパターンです。
実はこれ、実務ではあまり推奨されません。
この記事では
- Request Spec の役割
- Controller / Query / Model の責務分離
- 実際のコード例
を初心者向けに解説します。
1. 初心者が書きがちなRequestSpec
まずはよくある書き方です。
it "同じグループのユーザーが取得できる" do
get "/api/v1/me/shared_group_users", headers: headers
expect(response).to have_http_status(:ok)
body = response.parsed_body
expect(body["shared_group_users"].size).to eq(1)
expect(body["shared_group_users"][0]["user_id"]).to eq(other_user.public_id)
end
さらにこんなテストを書きがちです。
- 同じグループのユーザー取得
- 自分自身を除外
- 空配列
- 並び順
- 集約ロジック
一見正しそうですが、実は問題があります。
2. なぜ問題なのか
理由は テストの責務が混ざるからです。
Request Spec は
HTTP
↓
Routing
↓
Controller
↓
DB
すべてを通るテストです。
つまり とても重いテストです。
この状態でロジック検証までやると、
問題1 テストが遅くなる
Request Spec は
- Controller
- DB
- Serializer
などすべて通るため Unit Testより圧倒的に遅いです。
CIで大量に実行するとかなり影響します。
問題2 変更コストが増える
例えば取得ロジックを変更したとき、
本来修正すべきは
SharedGroupUsersQuery
ですが、
Query Spec
Request Spec
両方直す必要が出ます。
つまり メンテナンスコストが増えるのです。
3. 実務でよくある責務分離
実務ではテストの責務を次のように分けることが多いです。
| テスト | 役割 |
|---|---|
| Request Spec | API契約をテスト |
| Query Spec | データ取得ロジックをテスト |
| Model Spec | ドメインロジックをテスト |
それぞれ詳しく見ていきます。
Request Spec
Request Spec は API契約を確認するテストです。
確認する内容は次のようなものです。
- HTTPステータス
- レスポンス形式
- 認証 / 認可
- OpenAPIスキーマ
例:
it "200を返し、レスポンスがOpenAPIスキーマに一致する" do
get "/api/v1/me/shared_group_users", headers: headers
expect(response).to have_http_status(:ok)
assert_response_schema_confirm(200)
end
とてもシンプルです。
ロジックはQuerySpecでテストする
取得ロジックは Query Spec に書きます。
describe SharedGroupUsersQuery do
it "同じグループのユーザーを取得する" do
result = described_class.call(user)
expect(result.size).to eq(1)
end
end
これなら
- Controller
- Routing
- HTTP
を通らないので 高速です。
5. テスト設計まとめ
テストは次のように分けると整理できます。
API契約をテスト
Query Spec
取得ロジックをテスト
Model Spec
ドメインロジックをテスト
まとめ
Request Spec でやるべきことは
- HTTPステータス
- レスポンス形式
- 認証
- OpenAPIスキーマ
だけです。
ロジックは
Query
Model
に任せましょう。
この責務分離を意識するだけで
- テストが速くなる
- 保守性が上がる
- レビューで指摘されにくくなる
というメリットがあります。
Railsのテストを書くときは
「このロジックはどこが責務か?」
を考えると綺麗に整理できます。
参考
-
RSpec Rails
https://github.com/rspec/rspec-rails -
Rails Testing Guide
https://guides.rubyonrails.org/testing.html -
Testing Pyramid
https://martinfowler.com/articles/practical-test-pyramid.html -
Committee(OpenAPIスキーマ検証)
https://github.com/interagent/committee