Comment utiliser Factory Girl pour générer un attachement de trombone?

119

J'ai le modèle Person qui a beaucoup d'images, où les images ont un champ de pièce jointe de trombone appelé data, une version abrégée affichée ci-dessous:

class Person
  has_many :images
  ...
end

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

La personne doit avoir au moins une image attachée.

Lorsque j'utilise FactoryGirl, j'ai un code semblable à ce qui suit:

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

(NB J'ai également essayé le code commenté ci-dessus a également été essayé) La plupart du temps, lorsque j'exécute des fonctionnalités de concombre, j'obtiens une erreur semblable à celle-ci:

Aucun fichier ou répertoire de ce type - /tmp/stream,9887,0.png (Errno :: ENOENT)

...

Parfois, les tests fonctionnent avec succès.

Quelqu'un peut-il me dire quel est le problème que j'ai ici ou comment ils utilisent FactoryGirl et Paperclip ensemble pour réaliser quelque chose comme ce que j'essaie de réaliser?

J'utilise Rails 3.

Laz
la source
2
Votez sur la question juste pour avoir utilisé Keyzer Soze comme nom de test!
Breno
Quand je fais cela ... les photos sont générées et placées dans le dossier public / system à chaque fois que j'exécute la suite de tests. Les photos ne sont pas détruites après l'exécution de la suite de tests. Est-ce que quelqu'un d'autre a remarqué cela?
Jwan622

Réponses:

86

Vous pouvez utiliser fixture_file_upload

include ActionDispatch::TestProcess dans votre assistant de test, voici un exemple d'usine:

include ActionDispatch::TestProcess

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

Dans l'exemple ci-dessus, spec/photos/test.pngdoit exister dans le répertoire racine de votre application avant d'exécuter vos tests.

Notez qu'il FactoryBots'agit d'un nouveau nom pour FactoryGirl.

DanS
la source
2
Cette réponse est tout à fait juste, mais il peut être plus clair de dire que l'inclusion de TestProcess doit être incluse avec l'usine et pas simplement dans votre spec_helper.
Andrew Hubbs
2
Merci pour la clarification, Andrew. Vous devrez peut-être également placer "include ActionDispatch :: TestProcess" avant le bloc FactoryGirl.define (ce qui n'est pas ce qui se passe dans ce résumé : gist.github.com/313121 ).
Sam
3
En outre, les { }sont obligatoires. Ça casse sans ça
bigpotato
3
Précision supplémentaire: le include ActionDispatch::TestProcessdoit être inséré tout en haut du fichier d'usine, à l' extérieur du FactoryGirl.define do...endbloc.
Frank Koehl
49

Nouvelle syntaxe FG et aucune inclusion nécessaire

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

ou, mieux encore,

factory :user do
  avatar { File.new("#{Rails.root}/spec/support/fixtures/image.jpg") } 
end
Neal
la source
2
J'aime ça, mais gardez à l'esprit que rails 4 supprime app / assets / images / rails.png, vous devrez donc tenir compte de ce changement :)
stephenmurdoch
38

Desmond Bowe de Pivotal Labs suggère d'éviter fixture_file_upload en raison de problèmes de fuite de mémoire. Au lieu de cela, vous devez définir les champs du trombone directement dans votre usine:

factory :attachment do
  supporting_documentation_file_name { 'test.pdf' }
  supporting_documentation_content_type { 'application/pdf' }
  supporting_documentation_file_size { 1024 }
  # ...
end
Rick Quantz
la source
Travaille pour moi. Aussi assez simple pour ne pas avoir besoin d'un fichier existant dans le dossier spec / test.
bibstha
2
En plus d'éviter les fuites de mémoire, les tests seront ainsi plus rapides.
evedovelli
Le billet de blog mentionné a été déplacé vers pivotal.io/blog
Karsten S.
Malheureusement, cela ne fonctionne pas avec la validation des pièces jointes content_type. Pour cela, vous avez besoin d'un objet fichier valide.
Karsten S.
25

J'ai utilisé le code dans l'essentiel ci-dessous:

Rails 2

http://gist.github.com/162881

Rails 3

https://gist.github.com/313121

deb
la source
1
Je me demande simplement les mêmes choses et cela fonctionne à merveille. Merci. Je l'ai mis dans un initialiseur.
Todd
1
À noter: l'essentiel ci-dessus utilise l'ancienne syntaxe FactoryGirl. La réponse DanS utilise la nouvelle syntaxe.
Andrew Hubbs
12
file { File.new(Rails.root.join('spec', 'fixtures', 'filename.png')) }
Matthew Deiters
la source
C'est la solution fonctionnelle la plus simple.
superluminaire
4

Essayez d'utiliser ActionController :: TestUploadedFile. Vous pouvez simplement définir la propriété file sur une instance de TestUploadedFile et paperclip devrait s'occuper du reste. Par exemple

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
la source
0

Les réponses ci-dessus dans certains cas peuvent aider, et celle-ci m'a aidé dans l'une de mes situations, mais lors de l'utilisation d'un Carrierwave, la solution précédente de cette question n'a pas fonctionné cette fois.

PREMIÈRE APPROCHE:

Pour moi, l'ajout d'un a after :createrésolu le problème pour moi comme ceci:

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

La configuration du fichier vidéo en ligne video_file { File.new("#{Rails.root}/spec/fixtures/sample.mp4") }n'a pas fonctionné et a signalé des erreurs.

DEUXIÈME APPROCHE:

Définissez une usine comme celle-ci (changez personal_filele nom de votre pièce jointe):

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

Et ajoutez ces lignes au config/environemnts/test.rb:

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

Que testez-vous exactement? Ce trombone réussira à joindre le fichier? Cela semble vraiment être un test que le trombone devrait gérer, pas votre application.

As-tu essayé

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

Nous utilisons Machinist au lieu de factory_girl et nous venons d'utiliser des choses comme

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

Cependant, nous ne testons pas vraiment beaucoup lorsque nous faisons cela, nous voulons généralement juste avoir un Imageobjet valide .

theIV
la source
J'ai des modèles qui nécessitent une association valide avec un modèle compatible Paperclip, lui-même avec une pièce jointe valide.
Eric