QA@IT

RSpec-railsでParamsにクラスのインスタンスをセットする方法

3137 PV

現在Rails3.2とRSpec-rails2.12でRSpecのテストを行っているのですが、paramsにどの様にして、オブジェクトをセットすればいいのかわからず、質問させていただきました。

具体的に現在の問題を例に説明させていただきます。

私はJSONファイルをアップロードして、それをもとにBlogモデルを作る。という処理を書いているコントローラ内のメソッドがあります。
このメソッドをテストするために、rspec-railsを使って以下の様なテストを書きました。

  describe "POST import_create" do
    it "jsonファイルを受信して、それをもとにBlogモデルが作成されていること" do
      blog_file = File.new("spec/fixtures/blog.json")
      upload = ActionDispatch::Http::UploadedFile.new({
        :filename => 'blog.json',
        :content_type => 'application/json',
        :tempfile => blog_file
      })
      post :import_create, {:file => upload,:user_id => 1}

      ………
   end

しかしこのテストを実行した結果、コントローラ内でエラーとなりました。
そのコントローラのソースを記述させていただきます。

  def import_create
    p params[:file] #=>"#<ActionDispatch::Http::UploadedFile:0x007fb14dcbd0a8>"
    p params[:file].class #=>"String"
    json_array = JSON.parse(params[:file].read.kconv(Kconv::UTF8, Kconv::UTF8)) #=>NoMethodError read
   end

ここで私が困っている事を書かせていただきます。
私はテストするためには params[:file]がActionDispatch::Http::UploadedFileクラスのインスタンスを返すことを期待しています。
しかしながら、上記のようにコントローラにわたってきたparams[:file]はStringクラスを返しています。
わたしはRSpecの書き方が悪いためにこの様な事になっていると考えています。

どのようにすればRSpecからparamsにクラスのインスタンスをセットできますか?
ご回答いただけると嬉しいです。

回答

Rails のコントローラのテストで、ファイルのアップロードを行う場合は Rack::Test::UploadedFile を使う必要があります。

blog_file = Rack::Test::UploadedFile.new("spec/fixtures/blog.json", "application/json")

post の実装 をたどっていくと ActionController::TestCase::Behavior#paramify_value を呼んでいて、これをみると、Array, Hash, Rack::Test::UploadedFile 以外のオブジェクトは to_param メソッドの返り値 (通常は String になる) に置き換えられてしまうようです。

編集 履歴 (0)
  • 自分もpry-navを使って、答えありきで場所をなんとか探し出せました。自分も答え無しでも探しだせる様になりたいですね。色々勉強になりました、ありがとうございます。 -
ウォッチ

この質問への回答やコメントをメールでお知らせします。