2

Documents クラスをテストしようとしています。次のファクトリを定義しました。

require 'factory_girl'

FactoryGirl.define do
  factory :document do
    user_id                 '6315'
    name                    'Test doc'
    description             'W9'
    filename                'test_doc.pdf'
    filetype                'file'
    filesize                500
  end

  factory :invalid_doc, parent: :document do
    filesize                5242900
  end
end

次のヘルパー メソッドを使用して、テスト内の適切な属性にアクセスします。

def build_attributes(*args)
  attrs = FactoryGirl.build(*args).attributes
  attrs.delete_if do |k, v| 
    ["id", "created_at", "updated_at"].member?(k)
  end
  paramify_values(attrs)
end

私が実行する各テストの前に:

before(:each) do
  login_as_admin
  @doc = @user.documents.create(FactoryGirl.attributes_for(:document))
end

@user はlogin_as_adminマクロで設定されます。私のテストでは、これを実行しています:

describe 'POST #create' do
  it "should create a new document" do
    expect{
      post :create, document: build_attributes(:document, user_id: @doc.user_id)
    }.to change(Document,:count).by(1)
  end

  it "should find the right user" do
    post :create, document: build_attributes(:document, user_id: @doc.user_id)
    assigns(:user).should eq(@user)
  end

  # some other tests...
end

前者のテストはこの記事で提案されたもので、後者はちょうど私が起こるべきだと思うものです。コントローラーのアクションは、インスタンスに次のものを割り当てています。

@user = User.find(document[:user_id])

だから、かなり標準的です。ただし、これらのテストはどちらも同じエラーをスローします。

Failure/Error: post :create, document: build_attributes(:document, user_id: @doc.user_id)
 NoMethodError:
   undefined method `original_filename' for nil:NilClass

しかし、私はそのメソッドを明示的に呼び出すことはありません。FactoryGirl が呼び出しているものですか? モデルは次のように記述されます。

attr_accessible :description, :filename, :filesize, :filetype, :name, :user_id

:filename単なる文字列です。ここで何がうまくいかないのでしょうか?私はファイルをアップロードするためにペーパークリップを使用していませんfile_field。パスを取得し、ファイルをコントローラー内の運用サーバーに保存しますが、このメソッドを呼び出すことはありません。

編集:

実際のコントローラーの説明が役立つと思います笑

def create
  uploaded_file = params[:document][:file]
  document = params[:document]
  document.delete(:file)
  @user = User.find(document[:user_id])
  filepath = Rails.root.join('documents', @user.company_id.to_s, @user.id.to_s, uploaded_file.original_filename)
  %x[ mkdir #{Rails.root.join('documents', @user.company_id.to_s)} ]
  %x[ mkdir #{Rails.root.join('documents', @user.company_id.to_s, @user.id.to_s)} ]
  File.open(filepath, 'wb') do |file|
    file.write(uploaded_file.read)
  end
  document[:filesize]= File.size(filepath)
  document[:filetype]= File.ftype(filepath)
  document[:filename] = uploaded_file.original_filename
  d =Document.new(document)
  d.save
  redirect_to :action => 'show', :id => user.id
end

この方法には多くの問題があると確信していることを覚えておいてください。私はそれをリファクタリングしてテストしようとしています。今のところ、私がやろうとしているのは、この最初の問題を乗り越えることだけです。original_filenameメソッドはどこかで呼び出されており、自分で定義していません。なぜ/どこで誰が見ることができますか?

4

2 に答える 2

3

original_filenameアップロードされたファイルのメソッドです。ラックのドキュメントを参照してください

filepath = Rails.root.join('documents', @user.company_id.to_s, @user.id.to_s, uploaded_file.original_filename)

document[:filename] = uploaded_file.original_filename

コントローラーでは、元のファイル名を取得しています。ファイルがアップロードされると、ストレージ用の醜い一時ファイル名が取得されるため、元のファイル名を使用して読みやすく正確にする必要があります。

fixture_file_uploadrspec でヘルパーを使用することを検討してください。仕様の例を次に示します。

    expect {
      post :create, document: attributes_for(:document, user_id: @doc.user_id, file: fixture_file_upload('spec/assets/documents/test_doc.pdf', 'appliation/pdf'))
    }.to change(Document, :count).by(1)

テストPDFを配置しますspec/assets/documents/test_doc.pdf

于 2013-02-07T21:27:00.563 に答える
0

使用できます

Rack::Multipart::UploadedFile.new(path) 

あなたのテストのために。

于 2013-10-17T12:55:23.953 に答える