使用Rspec测试控制器(模型有validates_attachment_presence)

时间:2013-11-14 04:24:18

标签: ruby-on-rails rspec

我在以下型号上运行rspec测试时遇到问题:

class Sound < ActiveRecord::Base
  belongs_to :user

  # for paperclip
  has_attached_file :sound_file

  # do not create a sound unless a sound file
  # is present
 validates_attachment_presence :sound_file
end

具体来说,我正在尝试测试创建路径。来自我的控制器:

def create
    @sound = Sound.create( sound_params )
    redirect_to sound_url(@sound)
end

private

def sound_params
   params.require(:sound).permit(
     :sound_file,
     :sound_name,
     :description,
     :location)
end

以下是我在sounds_controller_spec.rb文件中首次编写的内容:

   describe "POST #create" do

     it 'creates a new sound' do 
       tester_sound = FactoryGirl.create(:sound,
                                     :sound_name => 'test',
                                     :sound_file => File.open('/Users/christopherspears/wdi/83746__braffe2__pen-writing.wav'))
       post :create, sound: tester_sound
       expect(Sound.last.sound_name).to eq(tester_sound[:sound_name])
     end
  end

我收到此错误消息:

  1) SoundsController POST #create creates a new sound
     Failure/Error: post :create, sound: tester_sound
     NoMethodError:
       undefined method `permit' for "54":String
       # ./app/controllers/sounds_controller.rb:53:in `sound_params'
       # ./app/controllers/sounds_controller.rb:16:in `create'
       # ./spec/controllers/sounds_controller_spec.rb:39:in `block (3 levels) in <top     (required)>'

奇怪的是,我认为'54'以某种方式连接到这个文件路径:/ Users / christopherspears / wdi / HearHere / public / system / sounds / sound_files / 000/000/054 / original / 83746_ braffe2 _pen-writing.wav

一位同事建议我只是将带有Sound参数的哈希传递给测试:

describe "POST #create" do 
    it 'creates a new sound' do 
      tester_hash = {:sound_name => 'test',
                     :sound_file =>  File.open('/Users/christopherspears/wdi/83746__braffe2__pen-writing.wav')}
    post :create, sound: tester_hash
    expect(Sound.last.sound_name).to eq(tester_hash[:sound_name])
   end
end

不幸的是,这又带来了另一个错误:

Failures:

  1) SoundsController POST #create creates a new sound
     Failure/Error: post :create, sound: tester_hash
     Paperclip::AdapterRegistry::NoHandlerError:
       No handler found for "#<File:0x007ff603de0868>"
     # ./app/controllers/sounds_controller.rb:16:in `create'
    # ./spec/controllers/sounds_controller_spec.rb:48:in `block (3 levels) in <top (required)>'

我认为我没有做任何不寻常的路线:

get 'sounds/:id/download' => 'sounds#download', :as => :download
resources :sounds

有什么建议吗?似乎用validates_attachment_presence测试模型的控制器将是一个挑战。

更新

我现在正在尝试不同的方法。

let(:valid_attributes) { { "sound_name" => "test", "sound_file" => File.new } }
let(:valid_session) { {} }

describe "POST #create" do 
    it 'creates a new sound' do
      sound = FactoryGirl.create(:sound => valid_attributes)
      expect { sound.sound_name }.to eq("test")
    end
end

好吧,至少我收到了不同的错误消息:

故障:

  1) SoundsController POST #create creates a new sound
     Failure/Error: let(:valid_attributes) { { "sound_name" => "test", "sound_file" => File.new } }
     ArgumentError:
       wrong number of arguments (0 for 1..3)
       # ./spec/controllers/sounds_controller_spec.rb:4:in `initialize'
       # ./spec/controllers/sounds_controller_spec.rb:4:in `new'
       # ./spec/controllers/sounds_controller_spec.rb:4:in `block (2 levels) in <top (required)>'
       # ./spec/controllers/sounds_controller_spec.rb:38:in `block (3 levels) in <top (required)>'

不确定是什么导致这个......

1 个答案:

答案 0 :(得分:0)

post期望其参数为nil哈希值或字符串,符合以下条件(取自https://github.com/rails/rails/blob/master/actionpack/lib/action_controller/test_case.rb),这就解释了为什么您的第一种方法无效。

  # Simulate a GET request with the given parameters.
  #
  # - +action+: The controller action to call.
  # - +parameters+: The HTTP parameters that you want to pass. This may
  #   be +nil+, a hash, or a string that is appropriately encoded
  #   (<tt>application/x-www-form-urlencoded</tt> or <tt>multipart/form-data</tt>).
  # - +session+: A hash of parameters to store in the session. This may be +nil+.
  # - +flash+: A hash of parameters to store in the flash. This may be +nil+.
  #
  # You can also simulate POST, PATCH, PUT, DELETE, HEAD, and OPTIONS requests with
  # +post+, +patch+, +put+, +delete+, +head+, and +options+.
  #
  # Note that the request method is not verified. The different methods are
  # available to make the tests more expressive.
  def get(action, *args)
    process(action, "GET", *args)
  end

  # Simulate a POST request with the given parameters and set/volley the response.
  # See +get+ for more details.
  def post(action, *args)
    process(action, "POST", *args)
  end

至于你的第二种方法,我预计它会失败,因为Paperclip希望:sound_file成为ActionDispatch::Http::UploadedFile的实例,如https://stackoverflow.com/a/11108270/1008891

中所述