👋

RSpecで空配列が欲しいのに空文字が混入する

2024/07/19に公開

ハコベル開発チームの坂東です。チームでモブプロをしながらRSpecを書いている最中に遭遇した挙動に困惑したので、備忘録も兼ねて記します。

環境

  • Rails: 7.0.8
  • RSpec: 6.1.2

RSpecで空配列が欲しいのに空文字が混入する

RSpecでリクエストスペックを書く際、空の配列をPOSTリクエストのパラメータとして送信すると、Railsがこれを空文字として解釈するケースがあります。

通らないテスト例

# spec/requests/posts_spec.rb
require 'rails_helper'

RSpec.describe "Posts", type: :request do
  describe "POST /posts" do
    context "when sending an empty array" do
      it "interprets the empty array as an empty array" do
        post '/posts', params: { ids: [] }

        # 出力されるparamsを確認
        puts request.params[:ids] # 期待: [], 実際: [""]

        expect(request.params[:ids]).to eq([])
      end
    end
  end
end

このテストは、空の配列[]を送信したつもりが、空文字列の配列[""]として解釈されてしまうため、失敗します。

原因と解決方法

この問題は、RspecがデフォルトのContent-Typeとしてapplication/x-www-form-urlencoded形式を想定していることに関係しています。

このContent -Typeの場合、空の配列は空文字列の配列として解釈されます。

この問題を回避するためには、リクエストの形式をJSONとして明示的に指定します。以下のように記述することで、空配列を正しく送信できます。

post '/posts', params: { ids: [] }, as: :json

修正後のテスト例

# spec/requests/posts_spec.rb
require 'rails_helper'

RSpec.describe "Posts", type: :request do
  describe "POST /posts" do
    context "when sending an empty array" do
      it "interprets the empty array as an empty array" do
        post '/posts', params: { ids: [] }, as: :json

        # 出力されるparamsを確認
        puts request.params[:ids] # 期待: [], 実際: []

        expect(request.params[:ids]).to eq([])
      end
    end
  end
end

この方法により、空配列が正しく送信され、期待通りの動作が得られます。

終わりに

以下でも述べられている通り、これは昔からハマる人がいる挙動のようです。

https://stackoverflow.com/questions/51396194/rspec-request-spec-post-an-empty-array

https://sinshutu-kibotu.hatenablog.jp/entry/2018/07/06/202132

これはバグではなく、RSpecのデフォルトの挙動によるものです。いざ遭遇すると原因が特定しづらいので、RSpecでテストを書く際は、このことを頭に入れておくと良いでしょう。

Hacobell Developers Blog

Discussion