2010-01-20 121 views
49

我期待的原始數據後(例如unparamaterized JSON)發送到我的控制器的一個測試:如何在Rails功能測試中發送原始發佈數據?

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

但是這給了我一個NoMethodError: undefined method `symbolize_keys' for #<String:0x00000102cb6080>錯誤。

ActionController::TestCase中發送原始發佈數據的正確方法是什麼?

下面是一些控制器代碼:

def index 
    post_data = request.body.read 
    req = JSON.parse(post_data) 
end 
+0

我很好奇你是如何做到這一點的,用於測試基於JSON的API。 – tadman 2010-01-20 18:49:34

回答

55

今天我遇到同樣的問題,並找到了解決方案。

在你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 

在你的功能測試,用它就像post方法,但將原始帖子正文作爲第三個參數。

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

我on Rails的2.3.4閱讀使用

request.body.read 

request.raw_post 

不是原始後身體的時候如果你看看source code你會看到raw_post測試這隻需在request env哈希中對request.body.read進行檢查即可。

+0

你搖滾,謝謝 – brian 2010-01-21 04:34:35

+1

這種方法在Rails 3.1中繼續正常工作 – cfeduke 2011-12-12 06:12:14

+1

呵呵,是啊和Rails 3.2也是如此。謝謝! – zigomir 2012-02-12 21:05:43

-5
post :index, {:foo=> 'bar', :bool => 'true'} 
+0

這不是原始的JSON,這是對它的散列解釋。 – tadman 2010-01-20 18:48:48

0

post方法需要的名稱 - 值對的哈希值,所以你需要做這樣的事情:

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

然後,在您的控制器中,獲取要解析的數據,如下所示:

post_data = params[:data] 
+0

我試過了,它需要是完全原始的,雖然 {「response」:「error」,「errors」:「無法解析請求:598:意外的令牌在'data = – brian 2010-01-20 19:23:36

+0

你如何解析JSON在你的控制器中?你能給你的問題添加一些控制器代碼嗎? – 2010-01-20 19:25:54

+0

好吧我現在要做到這一點 – brian 2010-01-20 19:31:55

15

我實際上解決了同樣的問題,只是在模擬rspec post請求之前添加一行 。你做什麼 是填充「RAW_POST_DATA」。我試圖刪除 post上的屬性var:create,但是如果我這樣做了, 它找不到該操作。

在這裏我的解決方案。

 
def do_create(attributes) 
    request.env['RAW_POST_DATA'] = attributes.to_json 
    post :create, attributes 
end 

在控制器中的代碼,你需要閱讀JSON是 與此類似

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

太棒了!只需一行,即使沒有發送過來的「屬性」,我也可以工作。 – 2013-07-12 22:41:38

+0

這工作的Rails 3.2.x,但似乎hack-ish。 RSpec應支持以JSON形式發佈的屬性。 Rspec的錯誤? – Tilo 2014-02-03 22:45:13

9

東西在堆棧跟蹤尋找運行的測試,你可以獲取有關要求編制更多的控制權: ActionDispatch: :集成:: RequestHelpers。後=>ActionDispatch::Integration::Session.process => Rack::Test::Session.env_for

可以傳遞JSON字符串:PARAMS和指定內容類型 「application/JSON」。在其他情況下,內容類型將被設置爲「application/x-www-form-urlencoded」,並且您的json將被正確解析。

因此,所有你需要的是指定 「CONTENT_TYPE」:

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

這對我不起作用。對於#「 – 2012-03-06 18:11:15

+0

」,我得到了一個像「undefined method' symbolize_keys'的錯誤,你可以看一下Rails的'post'源代碼(它調用'process')。如果動作之後的第一個參數是一個String,它將被讀爲'RAW_POST_DATA'。 – 2014-08-03 21:39:22

+0

這適用於Rails 4+,而不是某些早期版本。 – 2016-03-24 23:55:25

4

如果您正在使用的RSpec(> = 2.12.0)和寫作要求規範,所包含的模塊ActionDispatch::Integration::Runner。如果您查看源代碼,您可以注意到post方法調用process,它接受rack_env參數。

所有這一切都意味着,你可以簡單地做你的規格如下:

#spec/requests/articles_spec.rb 

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

和Controller:

#app/controllers/articles_controller.rb 

def create 
    puts request.body.read 
end 
+1

這隻適用於集成測試,不適用於從ActionController :: TestCase擴展的功能測試。 – bibstha 2014-10-16 22:46:36

1

使用Rails 4,我一直在尋找這樣做是爲了測試處理髮布到控制器的原始xml。我可以通過只提供字符串後做到這一點:

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

我相信,如果提供的參數是一個字符串,它只是被一起到控制器的身體傳遞。

+0

我不知道你爲什麼會陷入低谷,這是對的。 'post'的第二個參數可以是一個String或IO,並且成爲主體。 – ZiggyTheHamster 2017-12-06 21:42:08

0

鐵軌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 

的URL在/賬戶/ 5 /命令/ 10 /項。這得到了傳遞的url參數以及JSON體。當然,如果訂單沒有嵌入,那麼你可以忽略params散列。

爲Rails 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 
    end 
end 
+0

String#to_json意味着你正在傳遞一個包含JSON的JSON字符串......這不可能是你想要的。 – ZiggyTheHamster 2017-12-06 21:36:10

2

版本:

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

here參見 - body字符串參數被視爲原始請求體。

2

對於使用Rails5 +集成測試中,(無證)的方式來做到這一點是通過一個字符串中把params參數,因此:

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

這在軌道5.1中停止工作。如果你看看request.body.read - 它是空的。 – 2018-03-05 10:48:37

0

在軌,5.1我下面的工作做的時候刪除請求,在人體所需的數據:在做集成測試時這僅適用於:

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

注意。

+0

刪除是底層庫中的一個錯誤。 https://github.com/rack-test/rack-test/issues/200 – 2018-03-05 10:45:34

相關問題