使用Rspec,我如何在Rails 3.0.11中测试我的控制器的JSON格式? [英] Using Rspec, how do I test the JSON format of my controller in Rails 3.0.11?

查看:137
本文介绍了使用Rspec,我如何在Rails 3.0.11中测试我的控制器的JSON格式?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我搜遍了网页,但是,唉,我似乎无法让Rspec正确发送内容类型,所以我可以测试我的JSON API。我使用的是RABL gem for templates,Rails 3.0.11和Ruby 1.9.2-p180。



我的curl输出,工作正常(应该是401 ,我知道):

  mrsnuggles:tmp gaahrdner $ curl -i -HAccept:application / json-X POST  - d @bleh http:// localhost:3000 / applications 
HTTP / 1.1 403 Forbidden
Content-Type:application / json; charset = utf-8
Cache-Control:no-cache
X-Ua-Compatible:IE = Edge
X-Runtime:0.561638
服务器:WEBrick / 1.3.1( Ruby / 1.9.2 / 2011-02-18)
日期:2012年3月6日星期二01:10:51 GMT
Content-Length:74
连接:Keep-Alive
Set-Cookie:_session_id = 8e8b73b5a6e5c95447aab13dafd59993;路径= /; HttpOnly

{status:error,message:您无权访问此页面。}

从我的一个测试用例中抽取样本:

 描述ApplicationsController do 
render_views
disconnect_sunspot

let(:application){Factory.create(:application)}

subject {application}

上下文JSONdo

描述创建新应用程序do

context未授权时do
在执行
之前执行$ b $ json = {:应用程序=> {:name => foo,:description => bar}}
request.env ['CONTENT_TYPE'] ='application / json'
request.env ['RAW_POST_DATA'] = json
post:create
end

它不应该允许创建应用程序do
Application.count.should == 0
end

它应该用403 do
response.status.should eq(403)
end

它应该在散列中有一个状态和消息键do
JSON.parse( response.body)[status] ==error
JSON.parse(response.body)[message] =〜/ authorized /
end
end

contextauthorizeddo
end
end
end
end

这些测试永远不会通过,我总是被重定向,而且我的内容类型始终是 text / html ,无论我如何指定键入我的前块:

 # no 
在做
之前:create,{},{:format => :json}
结束

#nada
在做
之前post:create,:format => Mime :: JSON
结束

#nuh uh

之前request.env ['ACCEPT'] ='application / json'
post:创建,{:foo => :bar}
end

以下是rspec输出:

 失败:

1)ApplicationsController JSON在未经授权的情况下创建新的应用程序时,应以403
响应失败/错误:response.status.should eq(403)

预计403
得到302

(使用==比较)
#./spec/controllers /applications_controller_spec.rb:31:in< top(required)>'block(5 levels)'

2)ApplicationsController JSON在未经授权的情况下创建一个新的应用程序应该有一个状态和消息键在散列
失败/错误:JSON.parse(response.body)[status] ==错误
JSON :: ParserError:
756:'< >< body>您正在< a href =http://test.host/>重定向< / a>。< / body>< / html>'
#./ spec / controllers / applications_controller_spec.rb:35:在

正如你所看到的,我得到了HTML格式的302重定向,即使我试图指定'application / json'。



这是我的 application_controller.rb , rescue_from位:

  class ApplicationController< ActionController :: Base 

rescue_from ActiveRecord :: RecordNotFound,:with => :not_found
$ b $ protect_from_forgery
helper_method:current_user $ b $ helper_method:remove_dns_record

rescue_from CanCan :: AccessDenied do | exception |
flash [:alert] = exception.message
respond_to do | format |
h = {:status => error,:message => exception.message}
format.html {redirect_to root_url}
format.json {render:json => h,:status => :禁止}
format.xml {render:xml => h,:status => :禁止}
结束
结束

私人

def not_found(例外)
respond_to do | format |
h = {:status => error,:message => exception.message}
format.html {render:file => #{RAILS_ROOT} /public/404.html,:status => :not_found}
format.json {render:json => h,:status => :not_found}
format.xml {render:xml => h,:status => :not_found}
end
end
end

并且 applications_controller.rb ,特别是我正在尝试测试的'create'动作。因为我正在使用 state_machine 并重写删除方法,所以此时相当难看。

  def创建
#这需要清理并使用accepting_attributes_for
@application = Application.new(params [:application])
@environments = params [:application] [:environment_ids]
@ application.environment_ids<< @environments,除非@ environments.blank?

if params [:site_bindings] ==new
@site = Site.new(:name => params [:application] [:name])
@ environments.each do | e |
@ site.siteenvs<< Siteenv.new(:environment_id => e)
结束
结束

if @site
@ application.sites<< @site
结束

如果@ application.save
if @site
@ site.siteenvs.each do | se |
appenv = @ application.appenvs.select {| e | e.environment_id == se.environment_id}
se.appenv = appenv.first
se.save
end
end
flash [:success] =新应用程序创建。
respond_with(@application,:location => @application)
else
渲染'new'
end

#超级臭臭:(
@ application.change_servers_on_appenvs(params [:servers])unless params [:servers] .blank?
@ application.save
end

我在这里查看源代码: https://github.com/rails/rails/blob/master/actionpack/lib/action_controller/metal/responder.rb ,它似乎应该回应正确,以及堆栈溢出的问题似乎有类似的问题和可能的解决方案,但没有为我工作。



我做错了什么?

解决方案

尝试移动:format 请求,如下所示:

 描述ApplicationsController 
render_views
disconnect_sunspot

let(:application){Factory.create(:application)}

subject {application}

contextJSONdo

描述创建新应用程序do

context未授权时do
it不应允许创建应用程序do
params = {:format => 'json',:application => {:name => foo,:description => bar}}
post:create,params
Expect(Application.count).to eq(0)
expect(response.status).to eq(403)
expect(JSON.parse(response.body)[status])。to eq(error)
expect(JSON.parse(response.body)[message])。 /)
结束


结束

上下文授权做
结束
结束
结束
end

让我知道它是怎么回事!多数民众赞成在我设置我的测试的方式,他们工作得很好!

I've scoured the web, but, alas, I just can't seem to get Rspec to correctly send content-type so I can test my JSON API. I'm using the RABL gem for templates, Rails 3.0.11, and Ruby 1.9.2-p180.

My curl output, which works fine (should be a 401, I know):

mrsnuggles:tmp gaahrdner$ curl -i -H "Accept: application/json" -X POST -d @bleh http://localhost:3000/applications
HTTP/1.1 403 Forbidden 
Content-Type: application/json; charset=utf-8
Cache-Control: no-cache
X-Ua-Compatible: IE=Edge
X-Runtime: 0.561638
Server: WEBrick/1.3.1 (Ruby/1.9.2/2011-02-18)
Date: Tue, 06 Mar 2012 01:10:51 GMT
Content-Length: 74
Connection: Keep-Alive
Set-Cookie: _session_id=8e8b73b5a6e5c95447aab13dafd59993; path=/; HttpOnly

{"status":"error","message":"You are not authorized to access this page."}

Sample from one of my test cases:

describe ApplicationsController do
  render_views
  disconnect_sunspot

  let(:application) { Factory.create(:application) }

  subject { application }

  context "JSON" do

    describe "creating a new application" do

      context "when not authorized" do
        before do
          json = { :application => { :name => "foo", :description => "bar" } }
          request.env['CONTENT_TYPE'] = 'application/json'
          request.env['RAW_POST_DATA'] = json
          post :create
        end 

        it "should not allow creation of an application" do
          Application.count.should == 0
        end 

        it "should respond with a 403" do
          response.status.should eq(403)
        end 

        it "should have a status and message key in the hash" do
          JSON.parse(response.body)["status"] == "error"
          JSON.parse(response.body)["message"] =~ /authorized/
        end 
      end 

      context "authorized" do
      end 
    end
  end
end

These tests never pass though, I always get redirected and my content-type is always text/html, regardless of how I seem to specify the type in my before block:

# nope
before do
  post :create, {}, { :format => :json }
end

# nada
before do
  post :create, :format => Mime::JSON
end

# nuh uh
before do
  request.env['ACCEPT'] = 'application/json'
  post :create, { :foo => :bar }
end

Here is the rspec output:

Failures:

  1) ApplicationsController JSON creating a new application when not authorized should respond with a 403
     Failure/Error: response.status.should eq(403)

       expected 403
            got 302

       (compared using ==)
     # ./spec/controllers/applications_controller_spec.rb:31:in `block (5 levels) in <top (required)>'

  2) ApplicationsController JSON creating a new application when not authorized should have a status and message key in the hash
     Failure/Error: JSON.parse(response.body)["status"] == "errors"
     JSON::ParserError:
       756: unexpected token at '<html><body>You are being <a href="http://test.host/">redirected</a>.</body></html>'
     # ./spec/controllers/applications_controller_spec.rb:35:in `block (5 levels) in <top (required)>'

As you can see I'm getting the 302 redirect for the HTML format, even though I'm trying to specify 'application/json'.

Here is my application_controller.rb, with the rescue_from bit:

class ApplicationController < ActionController::Base

 rescue_from ActiveRecord::RecordNotFound, :with => :not_found

  protect_from_forgery
  helper_method :current_user
  helper_method :remove_dns_record

 rescue_from CanCan::AccessDenied do |exception|
    flash[:alert] = exception.message
    respond_to do |format|
      h = { :status => "error", :message => exception.message }
      format.html { redirect_to root_url }
      format.json { render :json => h, :status => :forbidden }
      format.xml  { render :xml => h, :status => :forbidden }
    end 
  end

  private

  def not_found(exception)
    respond_to do |format|
      h = { :status => "error", :message => exception.message }
      format.html { render :file => "#{RAILS_ROOT}/public/404.html", :status => :not_found }
      format.json { render :json => h, :status => :not_found }
      format.xml  { render :xml => h, :status => :not_found }
    end
  end
end

And also applications_controller.rb, specifically the 'create' action which is what I'm trying to test. It's fairly ugly at the moment because I'm using state_machine and overriding the delete method.

  def create
    # this needs to be cleaned up and use accepts_attributes_for
    @application = Application.new(params[:application])
    @environments = params[:application][:environment_ids]
    @application.environment_ids<<@environments unless @environments.blank?

    if params[:site_bindings] == "new"
      @site = Site.new(:name => params[:application][:name])
      @environments.each do |e|
        @site.siteenvs << Siteenv.new(:environment_id => e)
      end
    end

    if @site
      @application.sites << @site
    end

    if @application.save
      if @site
        @site.siteenvs.each do |se|
          appenv = @application.appenvs.select {|e| e.environment_id == se.environment_id }
          se.appenv = appenv.first
          se.save
        end
      end
      flash[:success] = "New application created."
      respond_with(@application, :location => @application)
    else
      render 'new'
    end

    # super stinky :(
    @application.change_servers_on_appenvs(params[:servers]) unless params[:servers].blank?
    @application.save
  end

I've looked at the source code here: https://github.com/rails/rails/blob/master/actionpack/lib/action_controller/metal/responder.rb, and it seems it should respond correctly, as well as a number of questions on stack overflow that seem to have similar issues and possible solutions, but none work for me.

What am I doing wrong?

解决方案

Try moving the :format key inside the params hash of the request, like this:

describe ApplicationsController do
  render_views
  disconnect_sunspot

  let(:application) { Factory.create(:application) }

  subject { application }

  context "JSON" do

    describe "creating a new application" do

      context "when not authorized" do
        it "should not allow creation of an application" do
          params = { :format => 'json', :application => { :name => "foo", :description => "bar" } }
          post :create, params 
          Expect(Application.count).to eq(0)
          expect(response.status).to eq(403)
          expect(JSON.parse(response.body)["status"]).to eq("error")
          expect(JSON.parse(response.body)["message"]).to match(/authorized/)
        end 


      end 

      context "authorized" do
      end 
    end
  end
end

Let me know how it goes! thats the way I have set my tests, and they are working just fine!

这篇关于使用Rspec,我如何在Rails 3.0.11中测试我的控制器的JSON格式?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆