Ruby-on-rails 如何对 JSON 控制器进行单元测试?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/8282116/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to unit-test a JSON controller?
提问by Yaron Naveh
This is my action:
这是我的操作:
def my_action
str = ... # get json str somehow
render :json => str
end
This is my test:
这是我的测试:
test "my test" do
post(:my_action, {'param' => "value"}
assert_response :success
end
I want to add another assertion that the emitted JSON contains some value. How can I do it in a controller unit-test, not via parsing the view result?
我想添加另一个断言,即发出的 JSON 包含一些值。我怎样才能在控制器单元测试中做到这一点,而不是通过解析视图结果?
回答by Simon Bagreev
Just like people commented above, this would be a functional test.
就像上面评论的人一样,这将是一个功能测试。
The best way would probably be making a request, parsing the JSON response body, and matching it to the expected result.
最好的方法可能是发出请求,解析 JSON 响应正文,并将其与预期结果匹配。
If I have companies_controllerin Rspec using FactoryGirl:
如果我companies_controller在 Rspec 中使用 FactoryGirl:
describe "GET 'show'" do
before(:each) do
@company = Factory(:company)
get 'show', :format => :json, :id => @company.id
end
it "should be successful" do
response.should be_success
end
it "should return the correct company when correct id is passed" do
body = JSON.parse(response.body)
body["id"].should == @company.id
end
end
You can test other attributes the same way. Also, I normally have invalidcontext where I would try to pass invalid parameters.
您可以以相同的方式测试其他属性。此外,我通常invalid会尝试传递无效参数的上下文。
回答by kendotwill
Using Rails' built-in functional test:
使用 Rails 的内置功能测试:
require 'test_helper'
class ZombiesControllerTest < ActionController::TestCase
setup do
@request.headers['Accept'] = Mime::JSON
@request.headers['Content-Type'] = Mime::JSON.to_s
end
test "should post my action" do
post :my_action, { 'param' => "value" }, :format => "json"
assert_response :success
body = JSON.parse(response.body)
assert_equal "Some returned value", body["str"]
end
end
回答by Jay Mitchell
My approach to this is slightly different if I'm using the Jbuildergem that is now available from the Rails team. (This approach applies to other gems that render JSONor XMLas views.) I prefer unit tests over functional tests whenever possible, since they can be quite a bit faster. With Jbuilder you can transform most of the tests into unit tests.
如果我使用JbuilderRails 团队现在提供的gem,我的方法会略有不同。(这种方法适用于将JSON或XML呈现为视图的其他 gem 。)我更喜欢单元测试而不是功能测试,因为它们可以快得多。使用 Jbuilder,您可以将大部分测试转换为单元测试。
Yes, you still have functional tests on the controller, but there are very few and they don't parse the JSON. The functional test solely test the controller logic, not the rendered JSON. A functional test for a valid request might assert the following (RSpec):
是的,您仍然对控制器进行了功能测试,但数量很少,而且它们不解析 JSON。功能测试仅测试控制器逻辑,而不是呈现的 JSON。有效请求的功能测试可能会断言以下内容 (RSpec):
assert_response :success
expect(response).to render_template(:show)
expect(assigns(:item).id).to eq(expected_item.id)
I'm just verifying that it is successful, it renders the template, and it passes the item to the template. At this point, the view has the information it needs to do the proper rendering.
我只是验证它是否成功,它呈现模板,并将项目传递给模板。此时,视图具有进行正确渲染所需的信息。
Now test the JSON rendered by unit testing the Jbuilder view.
现在测试通过单元测试 Jbuilder 视图呈现的 JSON。
describe 'api/v1/items/show.json.jbuilder' do
it 'includes foo' do
assign(:item, account.build(foo: 'bar'))
render
json = JSON.parse(rendered)
expect(json['item']['foo']).to eq('bar')
end
# A bunch of other JSON tests...
回答by joshneipp
This controller test worked well for me using Minitest with Rails 4.2.4:
这个控制器测试对我使用 Minitest 和 Rails 4.2.4 效果很好:
require 'test_helper'
class ThingsControllerTest < ActionController::TestCase
test "should successfully create a new thing" do
assert_difference 'Thing.count' do
@request.headers["Accept"] = "application/json"
post(:create, {thing: {name: "My Thing"}})
end
assert_response :success
json_response = JSON.parse(@response.body)
assert_equal json_response["name"], "My Thing"
end
end
And this worked in the form of an integration test.
这以集成测试的形式工作。
require 'test_helper'
class ThingsRequestsTest < ActionDispatch::IntegrationTest
test "creates new thing" do
assert_difference 'Thing.count' do
post("/things.json", {thing: { name: "My Thing"}})
end
assert_equal 201, status
json_response = JSON.parse(@response.body)
assert_equal json_response["name"], "My Thing"
end
end
Honestly, it's weird trying to keep the syntactical nuances straight from one type of test to another.
老实说,试图将语法上的细微差别直接从一种类型的测试保持在另一种类型的测试中是很奇怪的。

