web-dev-qa-db-fra.com

Comment envoyer des données de publication brutes dans un test fonctionnel Rails?

Je souhaite envoyer des données de publication brutes (par exemple, JSON non paramétré) à l'un de mes contrôleurs pour les tester:

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

mais cela me donne une erreur NoMethodError: undefined method `symbolize_keys' for #<String:0x00000102cb6080>.

Quelle est la bonne façon d’envoyer des données de publication brutes dans ActionController::TestCase?

Voici un code de contrôleur:

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

J'ai rencontré le même problème aujourd'hui et j'ai trouvé une solution.

Dans votre test_helper.rb, définissez la méthode suivante à l'intérieur 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

Dans votre test fonctionnel, utilisez-le comme la méthode post, mais transmettez le corps de publication brut en tant que troisième argument.

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

J'ai testé cela sur Rails 2.3.4 lors de la lecture du corps de message brut à l'aide de 

request.raw_post

au lieu de

request.body.read

Si vous regardez le code source vous verrez que raw_post encapsule simplement request.body.read avec une vérification de ce RAW_POST_DATA dans la valeur de hachage request env.

55
bbrowning

J'ai en fait résolu les mêmes problèmes en ajoutant une ligne Avant de simuler la demande de publication rspec. Ce que vous faites remplit "RAW_POST_DATA". J'ai essayé de supprimer Les attributs var sur le post: créer, mais si je le fais, Il ne trouve pas l'action.

Voici ma solution.

 def do_create (attributs) 
 request.env ['RAW_POST_DATA'] = attributs.to_json 
 post: créer, attributs 
 fin 

Dans le contrôleur, le code dont vous avez besoin pour lire le JSON est Quelque chose de similaire à ceci

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

En examinant la trace de pile exécutant un test, vous pouvez acquérir davantage de contrôle sur la préparation de la demande: ActionDispatch :: Integration :: RequestHelpers.post => ActionDispatch :: Integration :: Session.process => (Rack :: Test :: Session.env_for } _

Vous pouvez transmettre une chaîne json en tant que: params ET spécifier un type de contenu "application/json". Dans d'autres cas, le type de contenu sera défini sur "application/x-www-form-urlencoded" et votre json sera analysé correctement.

Il suffit donc de spécifier "CONTENT_TYPE":

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

Si vous utilisez RSpec (> = 2.12.0) et écrivez les spécifications de la demande, le module inclus est ActionDispatch::Integration::Runner. Si vous regardez le code source, vous remarquerez que le post appelle la méthode process qui accepte un paramètre rack_env

Tout cela signifie que vous pouvez simplement faire ce qui suit dans vos spécifications:

#spec/requests/articles_spec.rb

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

Et dans le contrôleur:

#app/controllers/articles_controller.rb

def create
  puts request.body.read
end
4

Pour ceux qui utilisent les tests d'intégration Rails5 +, la méthode (non documentée) consiste à passer une chaîne dans l'argument params, par exemple:

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

Version pour Rails 5: 

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

Voir ici - body Le paramètre de chaîne est traité comme un corps de requête brute.

2
Artem Vasiliev

En utilisant Rails 4, je cherchais à faire cela pour tester le traitement du xml brut qui était envoyé au contrôleur. J'ai pu le faire en fournissant simplement la chaîne au message:

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

Je crois que si le paramètre fourni est une chaîne, elle est simplement transmise au contrôleur en tant que corps.

1
Tom Rossi

La méthode post attend un hachage de paires nom-valeur. Vous devrez donc faire quelque chose comme ceci:

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

Ensuite, dans votre contrôleur, obtenez les données à analyser comme ceci:

post_data = params[:data]
0
Alex Reisner

À partir de Rails 4.1.5, c'était la seule chose qui fonctionnait pour moi:

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

pour une URL à/accounts/5/orders/10/items. Cela récupère les paramètres de l’URL ainsi que le corps JSON. Bien sûr, si les commandes ne sont pas intégrées, vous pouvez ne pas utiliser le hachage 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
Andrew Goodnough

Dans Rails, 5.1, les tâches suivantes s’effectuent pour moi lorsqu’une requête de suppression nécessitant des données dans le corps: 

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

REMARQUE: Ceci ne fonctionne que lors d'un test d'intégration.

0
Juan Gomez

Je cherchais depuis très longtemps comment publier du contenu JSON brut dans un test d'intégration (Rails 5.1). Je suppose que ma solution pourrait également aider dans ce cas… .. J'ai consulté la documentation et le code source de la méthode post: https://api.rubyonrails.org/v5.1/classes/ActionDispatch/Integration/RequestHelpers .html # method-i-post

Cela m'a dirigé vers la méthode process pour plus de détails: https://api.rubyonrails.org/v5.1/classes/ActionDispatch/Integration/Session.html#method-i-process

Grâce à cela, j'ai enfin découvert quels paramètres sont acceptés par la méthode process et donc post . Voici à quoi ressemblait ma solution finale:

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