如何使用RSpec检查JSON响应?

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

format.json { render :json => { :flashcard => @flashcard, :lesson => @lesson, :success => true } 

在我的RSpec控制器testing中,我想validation某个场景是否收到成功的json响应,所以我有以下行:

 controller.should_receive(:render).with(hash_including(:success => true)) 

虽然当我运行我的testing时,我得到以下错误:

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

我是否检查错误?

您可以检查响应对象并validation它是否包含期望的值:

 @expected = { :flashcard => @flashcard, :lesson => @lesson, :success => true }.to_json get :action # replace with action name / params as necessary response.body.should == @expected 

编辑

改变这个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 

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

你可以像这样parsing响应体:

 parsed_body = JSON.parse(response.body) 

然后,您可以对parsing的内容进行断言。

 parsed_body["foo"].should == "bar" 

基于凯文·特罗布里奇的回答

 response.header['Content-Type'].should include 'application/json' 

还有json_specgem,值得一看

https://github.com/collectiveidea/json_spec

简单和容易的方式来做到这一点。

 # 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 

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

 response.header['Content-Type'].should include 'text/javascript' 

另一种只针对JSON响应(而不是内部内容包含期望值)进行testing的方法是使用ActiveSupportparsing响应:

 ActiveSupport::JSON.decode(response.body).should_not be_nil 

如果响应不可parsingJSON,则将引发exception,并且testing将失败。

当使用Rails 5(目前还处于testing阶段)时,testing响应中会有一个新的方法parsed_body ,它将返回parsing的响应,作为最后一个请求的编码。

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

你也可以在spec/support/

 module ApiHelpers def json_body JSON.parse(response.body) end end RSpec.configure do |config| config.include ApiHelpers, type: :request end 

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

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

 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 

我在这里find了一个客户匹配器: https : //raw.github.com/gist/917903/92d7101f643e07896659f84609c117c4c279dfad/have_content_type.rb

把它放在spec / support / matchers / have_content_type.rb中,并确保从你的支持中加载这样的东西spec / spec_helper.rb

 Dir[Rails.root.join('spec/support/**/*.rb')].each {|f| require f} 

这里是代码本身,以防万一它从给定的链接消失。

 RSpec::Matchers.define :have_content_type do |content_type| CONTENT_HEADER_MATCHER = /^(.*?)(?:; charset=(.*))?$/ chain :with_charset do |charset| @charset = charset end match do |response| _, content, charset = *content_type_header.match(CONTENT_HEADER_MATCHER).to_a if @charset @charset == charset && content == content_type else content == content_type end end failure_message_for_should do |response| if @charset "Content type #{content_type_header.inspect} should match #{content_type.inspect} with charset #{@charset}" else "Content type #{content_type_header.inspect} should match #{content_type.inspect}" end end failure_message_for_should_not do |model| if @charset "Content type #{content_type_header.inspect} should not match #{content_type.inspect} with charset #{@charset}" else "Content type #{content_type_header.inspect} should not match #{content_type.inspect}" end end def content_type_header response.headers['Content-Type'] end end