tutorial test rails practices elaborando crear con best apis ruby-on-rails json testing

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''}