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

where: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_upload在 rspec 中使用帮助程序。这是一个示例规范:

    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 回答