如何使用RSpec检查JSON响应?

Fiz*_*izz 142 json rspec ruby-on-rails

我的控制器中有以下代码:

format.json { render :json => { 
        :flashcard  => @flashcard,
        :lesson     => @lesson,
        :success    => true
} 
Run Code Online (Sandbox Code Playgroud)

在我的RSpec控制器测试中,我想验证某个场景确实收到了成功的json响应,所以我有以下行:

controller.should_receive(:render).with(hash_including(:success => true))
Run Code Online (Sandbox Code Playgroud)

虽然当我运行我的测试时,我收到以下错误:

Failure/Error: controller.should_receive(:render).with(hash_including(:success => false))
 (#<AnnoController:0x00000002de0560>).render(hash_including(:success=>false))
     expected: 1 time
     received: 0 times
Run Code Online (Sandbox Code Playgroud)

我是否错误地检查了回复?

zet*_*tic 162

您可以检查响应对象并验证它是否包含预期值:

@expected = { 
        :flashcard  => @flashcard,
        :lesson     => @lesson,
        :success    => true
}.to_json
get :action # replace with action name / params as necessary
response.body.should == @expected
Run Code Online (Sandbox Code Playgroud)

编辑

将其更改为a post会使其变得有点棘手.这是一种处理它的方法:

 it "responds with JSON" do
    my_model = stub_model(MyModel,:save=>true)
    MyModel.stub(:new).with({'these' => 'params'}) { my_model }
    post :create, :my_model => {'these' => 'params'}, :format => :json
    response.body.should == my_model.to_json
  end
Run Code Online (Sandbox Code Playgroud)

请注意,mock_model不会响应to_json,因此需要一个stub_model或一个真实的模型实例.

  • JSON只是一个字符串,一系列字符及其顺序很重要.`{"a":"1","b":"2"}`和`{"b":"2","a":"1"}`不是表示相同对象的相等字符串.你不应该比较字符串而是对象,做`JSON.parse('{"a":"1","b":"2"}').should == {"a"=>"1","b "=>"2"}`而不是. (7认同)
  • 您还应该指定要请求的格式.`post:create,:format =>:json` (4认同)

bre*_*c79 158

您可以像这样解析响应主体:

parsed_body = JSON.parse(response.body)
Run Code Online (Sandbox Code Playgroud)

然后,您可以针对已解析的内容进行断言.

parsed_body["foo"].should == "bar"
Run Code Online (Sandbox Code Playgroud)

  • 你也可以使用`b = JSON.parse(response.body,symoblize_names:true)`这样你就可以使用这样的符号来访问它们:`b [:foo]` (8认同)
  • 这看起来好多了.谢谢. (6认同)
  • 如果JSON字符串中有数组,JSON.parse只返回一个数组. (4认同)
  • @PriyankaK如果它返回HTML,那么你的回复不是json.确保您的请求指定了json格式. (2认同)

lig*_*yrs 45

建立凯文特罗布里奇的答案

response.header['Content-Type'].should include 'application/json'
Run Code Online (Sandbox Code Playgroud)

  • rspec-rails为此提供了一个匹配器:expect(response.content_type).to eq("application/json") (20认同)
  • 难道你不能只使用`Mime :: JSON`而不是`'application/json'`? (4认同)

acw*_*acw 34

还有json_spec宝石,值得一看

https://github.com/collectiveidea/json_spec


Chi*_*iya 12

简单易行的方法.

# set some variable on success like :success => true in your controller
controller.rb
render :json => {:success => true, :data => data} # on success

spec_controller.rb
parse_json = JSON(response.body)
parse_json["success"].should == true
Run Code Online (Sandbox Code Playgroud)


Lor*_*lor 10

您也可以在里面定义一个辅助函数 spec/support/

module ApiHelpers
  def json_body
    JSON.parse(response.body)
  end
end

RSpec.configure do |config| 
  config.include ApiHelpers, type: :request
end
Run Code Online (Sandbox Code Playgroud)

json_body在需要访问JSON响应时使用.

例如,在您的请求规范中,您可以直接使用它

context 'when the request contains an authentication header' do
  it 'should return the user info' do
    user  = create(:user)
    get URL, headers: authenticated_header(user)

    expect(response).to have_http_status(:ok)
    expect(response.content_type).to eq('application/vnd.api+json')
    expect(json_body["data"]["attributes"]["email"]).to eq(user.email)
    expect(json_body["data"]["attributes"]["name"]).to eq(user.name)
  end
end
Run Code Online (Sandbox Code Playgroud)


小智 7

您可以查看'Content-Type'标题以查看它是否正确?

response.header['Content-Type'].should include 'text/javascript'
Run Code Online (Sandbox Code Playgroud)


Cli*_*ton 7

另一种测试JSON响应的方法(不是内容中的内容包含预期值)是使用ActiveSupport解析响应:

ActiveSupport::JSON.decode(response.body).should_not be_nil
Run Code Online (Sandbox Code Playgroud)

如果响应不可解析JSON,则抛出异常并且测试将失败.


Koe*_*en. 5

使用Rails 5(当前仍处于beta)时,parsed_body在测试响应上有一个新方法,该方法将返回解析为最后一个请求编码的响应。

在GitHub上的提交:https : //github.com/rails/rails/commit/eee3534b