web-dev-qa-db-ja.com

Rails機能テストで未加工の投稿データを送信するには?

私は、テストのために未加工の投稿データ(例:パラメータ化されていないJSON)をコントローラーの1つに送信したいと考えています。

class LegacyOrderUpdateControllerTest < ActionController::TestCase
  test "sending json" do
    post :index, '{"foo":"bar", "bool":true}'
  end
end

しかし、これは私にNoMethodError: undefined method `symbolize_keys' for #<String:0x00000102cb6080>エラーを与えます。

ActionController::TestCaseで生の投稿データを送信する正しい方法は何ですか?

コントローラーコードは次のとおりです。

def index
  post_data = request.body.read
  req = JSON.parse(post_data)
end
53
brian

今日同じ問題に出くわし、解決策を見つけました。

test_helper.rbで、ActiveSupport::TestCase内で次のメソッドを定義します。

def raw_post(action, params, body)
  @request.env['RAW_POST_DATA'] = body
  response = post(action, params)
  @request.env.delete('RAW_POST_DATA')
  response
end

機能テストでは、postメソッドと同じように使用しますが、3番目の引数として生の投稿本文を渡します。

class LegacyOrderUpdateControllerTest < ActionController::TestCase
  test "sending json" do
    raw_post :index, {}, {:foo => "bar", :bool => true}.to_json
  end
end

私はこれをRails 2.3.4を使用して未加工の投稿本文を読み取るときにテストしました

request.raw_post

の代わりに

request.body.read

ソースコード を見ると、raw_postrequest.body.readをラップし、request envでこのRAW_POST_DATAをチェックしていることがわかります。ハッシュ。

55
bbrowning

実際に、rspec post要求をシミュレートする前に1行追加するだけで同じ問題を解決しました。あなたがすることは、「RAW_POST_DATA」を投入することです。 post:createで属性varを削除しようとしましたが、削除してもアクションが見つかりません。

ここで私の解決策。

 def do_create(attributes)
 request.env ['RAW_POST_DATA'] = attributes.to_json 
 post:create、attributes 
 end 

コントローラでは、JSONを読み取るために必要なコードは次のようなものです

 @property = Property.new(JSON.parse(request.body.read))
18
Andrea Reginato

テストを実行しているスタックトレースを見ると、リクエストの準備をより細かく制御できます:ActionDispatch :: Integration :: RequestHelpers.post => ActionDispatch :: Integration :: Session.process => Rack :: Test :: Session.env_for

Json文字列を:paramsとして渡し、コンテンツタイプ「application/json」を指定できます。それ以外の場合、コンテンツタイプは「application/x-www-form-urlencoded」に設定され、jsonは適切に解析されます。

したがって、必要なのは「CONTENT_TYPE」を指定することだけです。

post :index, '{"foo":"bar", "bool":true}', "CONTENT_TYPE" => 'application/json'
9
Grimmo

Rails5 +統合テストを使用している場合、これを行う(文書化されていない)方法は、params引数に文字列を渡すことです。

post '/path', params: raw_body, headers: { 'Content-Type' => 'application/json' }
7
Rich

Rails 5のバージョン:

post :create, body: '{"foo": "bar", "bool": true}'

here を参照してください。body文字列パラメーターは、未加工の要求本文として扱われます。

4
Artem Vasiliev

RSpec(> = 2.12.0)を使用してリクエスト仕様を記述している場合、含まれるモジュールはActionDispatch::Integration::Runner。ソースコードを見ると、 post メソッドが process を呼び出し、rack_envパラメータ。

これはすべて、仕様で次のことを簡単に行えることを意味します。

#spec/requests/articles_spec.rb

post '/articles', {}, {'RAW_POST_DATA' => 'something'}

そしてコントローラーで:

#app/controllers/articles_controller.rb

def create
  puts request.body.read
end

Rails 4、

raw_xml = File.read("my_raw.xml")
post :message, raw_xml, format: :xml

提供されたパラメーターが文字列である場合、本体としてコントローラーに渡されるだけだと思います。

1
Tom Rossi

postメソッドは、名前と値のペアのハッシュを想定しているため、次のようにする必要があります。

post :index, :data => '{"foo":"bar", "bool":true}'

次に、コントローラーで、次のように解析するデータを取得します。

post_data = params[:data]
0
Alex Reisner

Rails 4.1.5の時点で、これが私のために働いた唯一のものでした:

class LegacyOrderUpdateControllerTest < ActionController::TestCase
  def setup
    @request.headers["Content-Type"] = 'application/json'
  end

  test "sending json" do
    post :index, '{"foo":"bar", "bool":true}'.to_json, { account_id: 5, order_id: 10 }
  end
end

/ accounts/5/orders/10/itemsのURL。これにより、JSON本体と同様に伝達されるurlパラメーターが取得されます。もちろん、注文が埋め込まれていない場合は、paramsハッシュを省略できます。

class LegacyOrderUpdateControllerTest < ActionController::TestCase
  def setup
    @request.headers["Content-Type"] = 'application/json'
  end

  test "sending json" do
    post :index, '{"foo":"bar", "bool":true}'.to_json
  end
end
0

Rails 5.1では、本文のデータを必要とする削除要求を行うときに次のように機能します。

delete your_app_url, as: :json, env: {
   "RAW_POST_DATA" =>  {"a_key" => "a_value"}.to_json
}

注:これは、統合テストを行う場合にのみ機能します。

0
Juan Gomez

統合テスト(Rails 5.1)で生のJSONコンテンツを投稿する方法を探していました。私のソリューションもこの場合に役立つと思います。 postメソッドのドキュメントとソースコードを検索しました。 https://api.rubyonrails.org/v5.1/classes/ActionDispatch/Integration/RequestHelpers.html#method-i- post

これにより、詳細についてprocessメソッドに導かれました。 https://api.rubyonrails.org/v5.1/classes/ActionDispatch/Integration/Session.html#method-i-process

これにより、process、したがってpostメソッドで受け入れられるパラメーターが最終的にわかりました。最終的な解決策は次のとおりです。

post my_url, params: nil, headers: nil, env: {'RAW_POST_DATA' => my_body_content}, as: :json
0
Peb