webentwicklung-frage-antwort-db.com.de

Wie versende ich Rohpostdaten in einem Rails-Funktionstest?

Ich freue mich darauf, Rohdaten (z. B. unparamaterisiertes JSON) an einen meiner Controller zu senden, um zu testen:

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

dies gibt mir jedoch einen NoMethodError: undefined method `symbolize_keys' for #<String:0x00000102cb6080>-Fehler.

Was ist der richtige Weg, um Rohdaten in ActionController::TestCase zu senden?

Hier ist ein Controller-Code:

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

Ich bin heute über das gleiche Problem gestoßen und habe eine Lösung gefunden.

Definieren Sie in Ihrem test_helper.rb die folgende Methode in 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

Verwenden Sie es in Ihrem Funktionstest genau wie die post-Methode, übergeben Sie jedoch den Roh-Post-Body als drittes Argument.

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

Ich habe dies auf Rails 2.3.4 getestet, als ich den rohen Pfostenkörper mit las 

request.raw_post

anstatt

request.body.read

Wenn Sie sich den source code ansehen, werden Sie feststellen, dass raw_post nur request.body.read mit einer Prüfung für diesen RAW_POST_DATA im request env-Hash umgibt.

55
bbrowning

Ich habe die gleichen Probleme gelöst, indem ich nur eine Zeile Vor der Simulation der Postanforderung von rspec hinzugefügt habe. Was Sie tun ist das Auffüllen der "RAW_POST_DATA". Ich habe versucht, Die Attribute var im Beitrag zu entfernen: create, aber wenn ich das tue, Finde die Aktion nicht.

Hier meine Lösung.

 def do_create (Attribute) 
 request.env ['RAW_POST_DATA'] = attributes.to_json 
 post: erstellen, Attribute 
 ende 

In der Steuerung lautet der Code, den Sie zum Lesen des JSON benötigen, __. Etwas ähnliches

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

Wenn Sie sich einen Stack-Trace ansehen, der einen Test ausführt, können Sie bei der Vorbereitung der Anforderung mehr Kontrolle erlangen: ActionDispatch :: Integration :: RequestHelpers.post => ActionDispatch :: Integration :: Session.process => Rack :: Test :: Session.env_for

Sie können json string wie folgt übergeben: params UND einen Inhaltstyp "application/json" angeben. In anderen Fällen wird der Inhaltstyp auf "application/x-www-form-urlencoded" gesetzt und Ihr Json wird ordnungsgemäß analysiert.

Sie müssen also nur "CONTENT_TYPE" angeben:

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

Wenn Sie RSpec (> = 2.12.0) verwenden und Anforderungsspezifikationen schreiben, ist das enthaltene Modul ActionDispatch::Integration::Runner. Wenn Sie sich den Quellcode ansehen, können Sie feststellen, dass die Methode postprocess aufruft, die einen rack_env-Parameter akzeptiert. 

All dies bedeutet, dass Sie in Ihrer Spezifikation einfach Folgendes tun können:

#spec/requests/articles_spec.rb

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

Und im Controller:

#app/controllers/articles_controller.rb

def create
  puts request.body.read
end

Für diejenigen, die Rails5 + -Integrationstests verwenden, besteht der (undokumentierte) Weg darin, eine Zeichenfolge im Argument params zu übergeben, also:

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

Version für Rails 5: 

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

Siehe hier - body Zeichenfolgenparameter wird als unformatierter Anforderungshauptteil behandelt.

2
Artem Vasiliev

Mit Rails 4 wollte ich die Verarbeitung von Roh-XML testen, die an den Controller gesendet wurde. Ich konnte es tun, indem ich einfach die Zeichenfolge für den Beitrag zur Verfügung stellte:

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

Ich glaube, wenn der angegebene Parameter eine Zeichenfolge ist, wird er als Körper an den Controller weitergegeben.

1
Tom Rossi

Die post-Methode erwartet einen Hash aus Name-Wert-Paaren, daher müssen Sie Folgendes tun:

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

Dann lassen Sie die Daten in Ihrem Controller folgendermaßen analysieren:

post_data = params[:data]
0
Alex Reisner

Ab Rails 4.1.5 war dies das einzige, was für mich funktionierte:

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

für eine URL unter/accounts/5/orders/10/items. Dadurch werden sowohl die URL-Parameter als auch der JSON-Body übermittelt. Wenn Orders nicht eingebettet sind, können Sie den Params-Hash natürlich weglassen.

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

In Rails, 5.1 haben Sie folgende Aufgaben, wenn Sie eine Löschanforderung ausführen, für die Daten im Rumpf erforderlich sind: 

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

HINWEIS: Dies funktioniert nur bei einem Integrationstest.

0
Juan Gomez

Ich habe lange gesucht, wie man rohe JSON-Inhalte in einem Integrationstest (Rails 5.1) bereitstellt. Ich denke, meine Lösung könnte auch in diesem Fall helfen ... Ich habe die Dokumentation und den Quellcode für die Methode post gesucht: https://api.rubyonrails.org/v5.1/classes/ActionDispatch/Integration/RequestHelpers .html # method-i-post

Dies verwies mich auf die process-Methode für weitere Details: https://api.rubyonrails.org/v5.1/classes/ActionDispatch/Integration/Session.html#method-i-process

Dank dessen habe ich endlich herausgefunden, welche Parameter von der process- und damit post-Methode akzeptiert werden ..__ So sah meine endgültige Lösung aus:

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