2012-03-06 3 views
54

私はウェブを精査しましたが、まあ、Rspecにコンテンツタイプを正しく送信させることができないため、JSON APIをテストできます。私はRABL gemをテンプレート、Rails 3.0.11、Ruby 1.9.2-p180に使用しています。Rspecを使用して、Rails 3.0.11でコントローラのJSON形式をテストするにはどうすればよいですか?

正常に動作します私のカール出力、(私が知っている、401でなければなりません):私のテスト例1から

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."} 

サンプル:

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 

これらのテストは、しかし、私を渡すことはありません前のブロックでどのようにタイプを指定しているかにかかわらず、常にリダイレクトされ、コンテンツタイプは常にtext/htmlです。

ここ

はRSpecの出力です:

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)>' 

あなたは私が「アプリケーション/ JSON」を指定しようとしているにもかかわらず、HTML形式のために302リダイレクトを取得しています見ることができるように。

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 

applications_controller.rb、私がテストしようとしているものです特に「を作成」アクション:ここ

はrescue_fromビットで、私のapplication_controller.rbです。 state_machineを使用していてdeleteメソッドをオーバーライドしているので、現時点ではかなり醜いです。

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 

私はここにソースコードを見てきました:https://github.com/rails/rails/blob/master/actionpack/lib/action_controller/metal/responder.rb、それは同様の問題と可能な解決策を持っているように見えるスタックオーバーフローに関する質問の数だけでなく、正しく応答しなければならないようだが、どれも作業私のために。

私は間違っていますか?

答えて

56

このように、要求のparamsハッシュ内:formatキーを移動してみてください:

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 

は、私はそれが行く方法を知ってみましょう!それは私のテストを設定している方法です、彼らはうまく動作しています!

+0

私はアーサーに戻ってくれてありがとう。テストをHTMLにリダイレクトする場合は、同じ結果が得られます 'ApplicationsController JSONは承認されていない場合に新しいアプリケーションを作成するとアプリケーションを作成できないようにしてください' '失敗/エラー:JSON.parse(response.body)["status"] == "errors" ' JSON :: ParserError: ' ' 756: 'の予期しないトークンredirectedです。 ' '#./spec/controllers/applications_controller_spec。rb:25:ブロック内(5レベル) '' – gaahrdner

+0

あなたのコントローラコードを見直しました!私は少しテストを変更しました!やってみて! –

+0

残念ながら、http://api.rubyonrails.org/classes/ActionController/TestCase/Behavior.html#method-i-postによると、どちらもうまくいきません。 'Content-Type'または' Accept'ヘッダを指定しなければ、Railsはデフォルトで 'text/html'になります。このcurl文と同様に、 'curl -i -X POST -d '{:アプリケーション=> {:name =>" foo "、:description =>" bar "}}' http:// localhost:3000/applications' – gaahrdner

61

:format => :jsonの設定が(上記の)1つの解決策であることを認識しています。しかし、私のAPIのクライアントが使用するのと同じ条件をテストしたかったのです。私のクライアントは:formatパラメータを設定しないで、代わりにAccept HTTPヘッダーを設定します。このソリューションに興味がある場合は、ここで私が使用したものをご紹介します。

+6

'request.accept =" application/json "を追加するだけで問題が解決しました。これは最も簡単な解決策のようです。ありがとう! – user3233065

+0

Rails 4とRspec 3.2.1が同じ問題を解決しました –

+0

Rails4とRspec3.3 –

関連する問題