¿Cómo utilizo Factory Girl para generar un clip adjunto?

119

Tengo una persona modelo que tiene muchas imágenes, donde las imágenes tienen un campo adjunto de clip de papel llamado datos, una versión abreviada que se muestra a continuación:

class Person
  has_many :images
  ...
end

class Image
  has_attached_file :data
  belongs_to :person
  ...
end

Se requiere que la persona tenga al menos una imagen adjunta.

Cuando uso FactoryGirl, tengo un código similar al siguiente:

Factory.define :image do |a|
  a.data { File.new(File.join(Rails.root, 'features', 'support', 'file.png')) }
  a.association :person
end

Factory.define :person do |p|
  p.first_name 'Keyzer'
  p.last_name 'Soze'
  p.after_create do |person|
    person.assets = [Factory.build(:image, :person => person)]
  end
  # p.images {|images| [images.association(:image)]}
end

(Nota: también probé el código comentado anteriormente) La mayoría de las veces cuando ejecuto funciones de pepino, aparece un error similar al siguiente:

No existe tal archivo o directorio - /tmp/stream,9887,0.png (Errno :: ENOENT)

...

A veces, las pruebas se ejecutan con éxito.

¿Alguien puede decirme cuál es el problema que tengo aquí o cómo usan FactoryGirl y Paperclip juntos para lograr algo como lo que estoy tratando de lograr?

Estoy usando Rails 3.

Laz
fuente
2
¡Vota a favor la pregunta solo por usar Keyzer Soze como nombre de prueba!
Breno
Cuando hago esto ... las fotos se generan y se colocan en la carpeta pública / del sistema cada vez que ejecuto el conjunto de pruebas. Las fotos no se destruyen una vez que la suite de pruebas termina de ejecutarse. ¿Alguien más nota esto?
Jwan622

Respuestas:

86

Puede usar fixture_file_upload

include ActionDispatch::TestProcess en su ayudante de prueba, aquí hay una fábrica de ejemplo:

include ActionDispatch::TestProcess

FactoryBot.define do
  factory :user do
    avatar { fixture_file_upload(Rails.root.join('spec', 'photos', 'test.png'), 'image/png') }
  end
end

En el ejemplo anterior, spec/photos/test.pngdebe existir en el directorio raíz de su aplicación antes de ejecutar sus pruebas.

Tenga en cuenta que FactoryBotes un nombre nuevo para FactoryGirl.

DanS
fuente
2
Esta respuesta es totalmente correcta, pero puede ser más claro decir que la inclusión de TestProcess debe incluirse con Factory y no simplemente en su spec_helper.
Andrew Hubbs
2
Gracias por la aclaración, Andrew. También puede tener que colocar "incluir ActionDispatch :: TestProcess" antes del bloque FactoryGirl.define (que no es lo que sucede en esta esencia: gist.github.com/313121 ).
Sam
3
Además, { }son obligatorios. Se rompe sin él
bigpotato
3
Aclaración adicional: include ActionDispatch::TestProcessdebe insertarse en la parte superior del archivo de fábrica, fuera del FactoryGirl.define do...endbloque.
Frank Koehl
49

Nueva sintaxis de FG y no es necesario incluir

factory :user do
  avatar { File.new(Rails.root.join('app', 'assets', 'images', 'rails.png')) }
end

o mejor aún,

factory :user do
  avatar { File.new("#{Rails.root}/spec/support/fixtures/image.jpg") } 
end
Neal
fuente
2
Me gusta, pero tenga en cuenta que rails 4 elimina app / assets / images / rails.png, por lo que deberá tener en cuenta ese cambio :)
stephenmurdoch
38

Desmond Bowe de Pivotal Labs sugiere evitar fixture_file_upload debido a problemas de pérdida de memoria. En su lugar, debe configurar los campos del clip directamente en su fábrica:

factory :attachment do
  supporting_documentation_file_name { 'test.pdf' }
  supporting_documentation_content_type { 'application/pdf' }
  supporting_documentation_file_size { 1024 }
  # ...
end
Rick Quantz
fuente
Funciona para mi. También lo suficientemente simple como para no requerir un archivo existente en la carpeta de especificaciones / pruebas.
bibstha
2
Además de evitar pérdidas de memoria, de esta forma las pruebas serán más rápidas.
evedovelli
La publicación de blog mencionada se movió a pivotal.io/blog
Karsten S.
Desafortunadamente, esto no funciona con la validación de archivos adjuntos activada content_type. Para eso necesita un objeto de archivo válido.
Karsten S.
25

He estado usando el código en la esencia a continuación:

Carriles 2

http://gist.github.com/162881

Carriles 3

https://gist.github.com/313121

debutante
fuente
1
Solo me pregunto las mismas cosas y esto funciona de maravilla. Gracias. Lo puse en un inicializador.
Todd
1
Algo a tener en cuenta: la esencia anterior usa la sintaxis anterior de FactoryGirl. La respuesta de DanS usa la nueva sintaxis.
Andrew Hubbs
12
file { File.new(Rails.root.join('spec', 'fixtures', 'filename.png')) }
Matthew Deiters
fuente
Ésta es la solución funcional más sencilla.
superluminario
4

Intente usar ActionController :: TestUploadedFile. Puede simplemente establecer la propiedad del archivo en una instancia de TestUploadedFile y el clip debe encargarse del resto. Por ejemplo

valid_file = File.new(File.join(Rails.root, 'features', 'support', 'file.png'))  
p.images { 
   [
     ActionController::TestUploadedFile.new(valid_file, Mime::Type.new('application/png'))
   ] 
}
Britt
fuente
0

Las respuestas anteriores en algunos casos pueden ayudar, y la que realmente ayudó en una de mis situaciones, pero al usar un Carrierwave, la solución anterior de esta pregunta no funcionó esta vez.

PRIMER ENFOQUE:

Para mí, agregando un after :createproblema resuelto para mí de esta manera:

after :create do |b|
  b.update_column(:video_file, File.join(Rails.root, 'spec', 'fixtures', 'sample.mp4'))
end

La configuración del archivo de video en línea como video_file { File.new("#{Rails.root}/spec/fixtures/sample.mp4") }no funcionó y estaba informando errores.

SEGUNDO ENFOQUE:

Defina una fábrica como esta (cambie personal_filea su nombre de archivo adjunto):

FactoryGirl.define do
  factory :contact do
    personal_file { File.new("#{Rails.root}/spec/fixtures/personal_files/my_test_file.csv") }
    personal_file_content_type 'text/csv'

  end
end

Y agregue estas líneas al config/environemnts/test.rb:

config.paperclip_defaults = {
  url: "#{Rails.root}/spec/fixtures/:attachment/:filename",
  use_timestamp: false
}
Aleks
fuente
-1

¿Qué estás probando exactamente? ¿Ese clip adjuntará correctamente el archivo? Eso realmente parece una prueba que debe manejar el clip, no su aplicación.

Has probado

a.data { File.join(Rails.root, 'features', 'support', 'file.png') }

Usamos Machinist en lugar de factory_girl y acabamos de usar cosas como

Image.blueprint do
  image { RAILS_ROOT + 'spec/fixtures/images/001.jpg' }
end

Sin embargo, en realidad no estamos probando mucho cuando hacemos esto, normalmente solo queremos tener un Imageobjeto válido .

el IV
fuente
Tengo modelos que requieren una asociación válida con un modelo habilitado para Paperclip, con un adjunto válido.
Eric