既存のクラスを拡張してメソッドを持たせる

■テストの際にも使える(例:ファイルアップのテスト)


ファイルアップは、multipartフォームが用いられ、malutipart/form-dataで扱われるオブジェクト
は、StringIO(大きいとFileになる?)であり、かつ、以下の3つのメソを持っている。

                                                      • -

・local_path
・original_filename
・content_type

                                                      • -

しかし、テストでFileオブジェクトを生成して、
post :upload :file => File.open(filename)のようにやっても、例えば、コントローラの方で、
params[:file].original_filenameとかの操作を行っていたらならば、当然、UndefMethodエラー
となる。


これを防止するために、IOを持つFileクラスのオブジェクトに、上記の3つのメソッドを追加して、
あたかもmultipartで送られてきたデータのように振舞わせる。
今回は、original_filenameだけを持たせてみる。

 def upload_file(filename)
    t = File.open(filename,"r")
   
    (class << t; self; end).class_eval do
      define_method(:original_filename){File.basename(filename)}
    end
   
    return t
  end


このように、クラスのファイルに書くのではなく、オブジェクトを生成してから書いている。


※オリジナルはこれ
http://wiki.rubyonrails.org/rails/pages/HowtoUploadFiles
または、「はじめようRuby on Raiks」p116



これを使ったCSVUPのテストはこんな感じ

   def test_upload
    previous_count = Student.count
    post :upload,:file => upload_file(File.dirname(__FILE__) + '/../../upload_files/test_upload.csv')
    assert_redirected_to :action => "list"
    assert_equal 2,assigns(:students).size
    assert_equal assigns(:students).size,assigns(:at_recs).size
    assert_equal previous_count + 2,Student.count
  end
  
  def upload_invalid_test(filename)
    previous_count = Student.count
    post :upload,:file => upload_file(File.dirname(__FILE__) + '/../../upload_files/' + filename)
    assert_template "csv_upload"
    assert_equal previous_count ,Student.count
  end
  
  def test_invalid_upload_with_invalid_filetype
    upload_invalid_test('test_upload.xls')
  end
  
  def test_invalid_upload_with_over_linesized_file
    upload_invalid_test('test_overline_upload.csv')
  end

  def test_invalid_upload_with_invalid_params
    upload_invalid_test('test_invalid_upload.csv')
  end