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
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.
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))
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'
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' }
Version für Rails 5:
post :create, body: '{"foo": "bar", "bool": true}'
Siehe hier - body
Zeichenfolgenparameter wird als unformatierter Anforderungshauptteil behandelt.
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.
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]
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
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.
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