如何使用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,值得一看
简单和容易的方式来做到这一点。
# 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