Testeando subida de archivos (file uploads) con Cucumber, Rspec y Paperclip +

Ultimamente estoy realizando una aplicación que requiere subir archivos Excel, fue un poco difícil encontrar la forma de que pasaran mis tests con Paperclip, pero hay que reconocer que esta gema hace magia con los uploads, el problema que tenía era con los uploads y el content_type, mi modelo realiza la validación del tipo de contenido usando las validaciones que provee paperclip, el modelo luce de esta forma:

class Archivo < ActiveRecord::Base

  before_create :adicionar_usuario

  belongs_to :usuario
  has_many :hojas

  validates_associated :usuario
  validates_presence_of :nombre
  validates_format_of :archivo_excel_file_name, :with => /\A^.+\.xls$\Z/i, :message => 'Solo se permite archivos excel ".xls"'

  attr_accessible :archivo_excel, :nombre, :descripcion

  has_attached_file :archivo_excel, :path => "archivos/:id/:basename.xls"

 # Validacion de tipos de contenido para excel
  validates_attachment_content_type :archivo_excel, :content_type => ['application/vnd.ms-excel'],
                        :message => ‘Solo se permite archivos Excel’
 #’application/x-msexcel’,'application/ms-excel’, ‘application/msexcel’, ‘application/x-excel’

  validates_attachment_presence :archivo_excel, :message => “Debe ingresar un archivo excel”

protected
  def adicionar_usuario
    self.usuario = UsuarioSession.find.record
  end

end

Además estoy usando Authlogic para hacer la autenticación, junto con shoulda. El test del modelo es de la siguiente forma:

require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')

describe Archivo do

  it{should belong_to(:usuario)}
  it{should validate_presence_of(:nombre)}

  before(:each) do

    archivo = File.join(RAILS_ROOT, 'ejemplos/VentasPrecio2000-2008.xls')
    up = ActionController::UploadedStringIO.new
    up.original_path = archivo
    up.content_type = 'application/vnd.ms-excel'
    @archivo_params = {
      :nombre => 'Excel',
      :archivo_excel => up
    }
    @usuario_mock = mock_model(Usuario, :id => 1, :nombre => 'Juan')
    Usuario.stub!(:find).with(kind_of(Fixnum)).and_return(@usuario_mock)
    @us = mock("record", :record => @usuario_mock)
    UsuarioSession.stub!(:find).and_return(@us)
  end

  def create_archivo
    @archivo = Archivo.create(@archivo_params)
  end

  it "debe crear" do
    a = Archivo.create!(@archivo_params)
  end

  it "debe guardar el usuario" do
    create_archivo()
    @archivo.usuario.id.should == 1
  end
end

Lo importante aquí está en cuando defino el before(:each) del test rspec, en el cual creo un mock ActionController::UploadedStringIO.new, despues defino la ruta y el tipo de content_type para el archivo que hago upload. Esta es la clave para poder hacer el subida del archivo y de que pase el test.

El problema para testear con Cucumber era mucho mas simple pero me llevo algún tiempo darme cuenta de ello (mi amigo Felix Carreño lo hizo), lo que sucedía era que Webrat tiene un comando para poder subir archivos en el cual solo se pasa el archivo que se desea subir y este asigna al file_field que uno define en el formulario, pero además uno debe indicar el tipo de conten_type, para que el test funcione y pase la validación de contenido de paperclip, osea solo es necesario hacerlo de esta forma:

#Archivo que uso para mi test
archivo = File.join(RAILS_ROOT, "ejemplos/VentasPrecio2000-2008.xls")
attach_file "archivo[archivo_excel]“, archivo, ‘application/vnd.ms-excel’

2 comentarios en “Testeando subida de archivos (file uploads) con Cucumber, Rspec y Paperclip”

  1. Hey Boris, parece que sin querer estamos trabajando en equipo =D Te dejo un link a mi tutorial sobre cómo instalar y configurar Paperclip: http://viarails.wordpress.com/2009/11/29/como-adjuntar-archivos-a-un-modelo-en-rails/

  2. En la parte del before(:each) en ves de usar la clase ActionController::UploadedStringIO
    se puede usar:
    up = ActionController::TestUploadedFile(’ejemplos/VentdasPrecio2000-2008.xls’, ‘application/vnd.ms-excel’)

Su comentario