如何在Railsfunctiontesting中发送原始数据?

我正在寻找发送原始的数据(例如非参数化的JSON)到我的一个控制器进行testing:

 类LegacyOrderUpdateControllerTest <ActionController :: TestCase
 testing“发送json”呢
    post:index,'{“foo”:“bar”,“bool”:true}'
 结束
结束

但是这给了我一个NoMethodError: undefined method `symbolize_keys' for #<String:0x00000102cb6080>

在ActionController :: TestCase中发送原始发布数据的正确方法是什么?

这是一些控制器代码

  def索引
     post_data = request.body.read
     req = JSON.parse(post_data)

我今天遇到同样的问题,find了一个解决scheme。

在你的test_helper.rb中定义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 

在你的functiontesting中,就像post方法一样使用它,但是传递原始的post体作为第三个参数。

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

我在Rails 2.3.4上testing了这个,当阅读原始的后身使用

 request.raw_post 

代替

 request.body.read 

如果您查看源代码,您将看到raw_post只是在请求env哈希中包装了request.body.read并检查了这个RAW_POST_DATA。

我实际上解决了相同的问题,只是在模拟rspec post请求之前添加一行。 你所做的是填充“RAW_POST_DATA”。 我试图删除后,创build属性var,但如果我这样做,它不会find该操作。

这里我的解决scheme

 def do_create(属性)
   request.env ['RAW_POST_DATA'] = attributes.to_json
  发表:创build,属性
结束 

在控制器中,您需要阅读JSON的代码与此类似

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

查看运行testing的堆栈跟踪,您可以获得更多的请求准备控制:ActionDispatch :: Integration :: RequestHelpers.post => ActionDispatch :: Integration :: Session.process => Rack :: Test :: Session.env_for

你可以传递jsonstring为:params并指定一个内容types“application / json”。 在其他情况下,内容types将被设置为“application / x-www-form-urlencoded”,你的json将被正确parsing。

所以你只需要指定“CONTENT_TYPE”:

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

如果使用RSpec(> = 2.12.0)并编写请求规范,则包含的模块是ActionDispatch::Integration::Runner 。 如果你看一下源代码,你可以注意到post方法调用的过程接受一个rack_env参数。

所有这一切意味着你可以简单地在你的规范中做到以下几点:

 #spec/requests/articles_spec.rb post '/articles', {}, {'RAW_POST_DATA' => 'something'} 

而在控制器中:

 #app/controllers/articles_controller.rb def create puts request.body.read end 

Rails 5版本:

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

看到这里 – body string参数被视为原始请求体。

post方法需要名称 – 值对的散列,所以你需要做这样的事情:

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

然后,在您的控制器中,获取要parsing的数据,如下所示:

 post_data = params[:data] 

从Rails 4.1.5开始,这是我唯一的工作:

 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 

在/帐户/ 5 /订单/ 10 /项目的url。 这得到了传递的url参数以及JSON体。 当然,如果订单没有embedded,那么你可以离开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 

对于那些使用Rails5 +集成testing的人来说,这样做的方式是在params参数中传递一个string,所以:

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

使用Rails 4,我期待这样做来testing正在发布到控制器的原始xml的处理。 我能够做到这一点,只是提供string的职位:

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

我相信,如果提供的参数是一个string,它只是作为正文传递给控制器​​。

在rails中,当执行一个需要数据的删除请求时5.1对我来说很有用:

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

注意:这只适用于进行集成testing。

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