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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 02:24:45  来源:igfitidea点击:

How to unit-test a JSON controller?

ruby-on-railsruby

提问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,我的方法会略有不同。(这种方法适用于将JSONXML呈现为视图的其他 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.

老实说,试图将语法上的细微差别直接从一种类型的测试保持在另一种类型的测试中是很奇怪的。