如何在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'}