ruby on rails - test - ¿Cómo enviar datos brutos de publicaciones en una prueba funcional de Rails?
rails api tutorial (11)
Estoy buscando enviar datos de entrada en bruto (por ejemplo, JSON sin parametrizar) a uno de mis controladores para probar:
class LegacyOrderUpdateControllerTest < ActionController::TestCase
test "sending json" do
post :index, ''{"foo":"bar", "bool":true}''
end
end
pero esto me da un NoMethodError: undefined method `symbolize_keys'' for #<String:0x00000102cb6080>
error NoMethodError: undefined method `symbolize_keys'' for #<String:0x00000102cb6080>
.
¿Cuál es la forma correcta de enviar datos sin procesar en ActionController::TestCase
?
Aquí hay un código de controlador:
def index
post_data = request.body.read
req = JSON.parse(post_data)
end
A partir de Rails 4.1.5, esto fue lo único que funcionó para mí:
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
para una url en / accounts / 5 / orders / 10 / items. Esto obtiene los parámetros de URL transmitidos, así como el cuerpo JSON. Por supuesto, si las órdenes no están incrustadas, entonces puedes dejar el hash de 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
De hecho, resolví los mismos problemas simplemente agregando una línea antes de simular la solicitud de rspec. Lo que debes hacer es llenar el "RAW_POST_DATA". Traté de eliminar los atributos var en la publicación: crear, pero si lo hago, no encuentro la acción.
Aquí mi solución.
def do_create(attributes) request.env[''RAW_POST_DATA''] = attributes.to_json post :create, attributes end
En el controlador, el código que necesita para leer el JSON es algo similar a este
@property = Property.new(JSON.parse(request.body.read))
El método de post
espera un hash de pares nombre-valor, por lo que tendrás que hacer algo como esto:
post :index, :data => ''{"foo":"bar", "bool":true}''
Luego, en su controlador, obtenga los datos para ser analizados de esta manera:
post_data = params[:data]
En rieles, 5.1 lo siguiente me funciona cuando hago una solicitud de eliminación que necesita datos en el cuerpo:
delete your_app_url, as: :json, env: {
"RAW_POST_DATA" => {"a_key" => "a_value"}.to_json
}
NOTA: Esto solo funciona cuando se realiza una prueba de integración.
Me encontré con el mismo problema hoy y encontré una solución.
En su test_helper.rb
defina el siguiente método dentro de 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
En su prueba funcional, utilícela igual que el método de post
, pero pase el cuerpo de publicación sin procesar como tercer argumento.
class LegacyOrderUpdateControllerTest < ActionController::TestCase
test "sending json" do
raw_post :index, {}, {:foo => "bar", :bool => true}.to_json
end
end
Probé esto en Rails 2.3.4 al leer el cuerpo del mensaje sin procesar usando
request.raw_post
en lugar de
request.body.read
Si miras el código fuente , verás que raw_post
simplemente envuelve request.body.read
con un cheque para este RAW_POST_DATA
en la request
env hash.
Para aquellos que usan Rails5 + pruebas de integración, la forma (no documentada) de hacer esto es pasar una cadena en el argumento params, entonces:
post ''/path'', params: raw_body, headers: { ''Content-Type'' => ''application/json'' }
Si observa el seguimiento de la pila ejecutando una prueba, puede adquirir más control en la preparación de la solicitud: ActionDispatch :: Integration :: RequestHelpers.post => ActionDispatch::Integration::Session.process => Rack::Test::Session.env_for
Puede pasar cadena json como: params Y especificar un tipo de contenido "application / json". En otro caso, el tipo de contenido se establecerá en "application / x-www-form-urlencoded" y su json se analizará correctamente.
Entonces, todo lo que necesita es especificar "CONTENT_TYPE":
post :index, ''{"foo":"bar", "bool":true}'', "CONTENT_TYPE" => ''application/json''
Si usa RSpec (> = 2.12.0) y escribe especificaciones de solicitud, el módulo que se incluye es ActionDispatch::Integration::Runner
. Si rack_env
un vistazo al código fuente, puedes notar que el método de post llama al process que acepta un parámetro rack_env
.
Todo esto significa que simplemente puede hacer lo siguiente en su especificación:
#spec/requests/articles_spec.rb
post ''/articles'', {}, {''RAW_POST_DATA'' => ''something''}
Y en el controlador:
#app/controllers/articles_controller.rb
def create
puts request.body.read
end
Usando Rails 4, estaba buscando hacer esto para probar el procesamiento de xml sin formato que se estaba publicando en el controlador. Pude hacerlo solo proporcionando la cadena a la publicación:
raw_xml = File.read("my_raw.xml")
post :message, raw_xml, format: :xml
Creo que si el parámetro proporcionado es una cadena, simplemente pasa al controlador como cuerpo.
Versión para Rails 5:
post :create, body: ''{"foo": "bar", "bool": true}''
Vea here - body
parámetro de cadena de body
se trata como cuerpo de solicitud sin procesar.
post :index, {:foo=> ''bar'', :bool => ''true''}