Come si usa Factory Girl per generare un allegato a graffetta?


119

Ho un modello Persona che ha molte immagini, in cui le immagini hanno un campo allegato Paperclip chiamato dati, una versione abbreviata visualizzata di seguito:

class Person
  has_many :images
  ...
end

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

La persona deve avere almeno un'immagine allegata.

Quando uso FactoryGirl, ho un codice simile al seguente:

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 Ho anche provato il codice commentato sopra è stato anche provato) La maggior parte delle volte quando eseguo le funzionalità di cetriolo, ottengo un errore simile al seguente:

Nessun file o directory di questo tipo - /tmp/stream,9887,0.png (Errno :: ENOENT)

...

A volte i test vengono eseguiti correttamente.

Qualcuno può dirmi qual è il problema che sto avendo qui o come usano FactoryGirl e Paperclip insieme per ottenere qualcosa come quello che sto cercando di ottenere?

Sto usando Rails 3.


2
Vota su domanda solo per aver usato Keyzer Soze come nome di prova!
Breno

Quando faccio questo ... le foto vengono generate e posizionate nella cartella public / system ogni volta che eseguo la suite di test. Le foto non vengono distrutte dopo che la suite di test è stata eseguita. Qualcun altro lo nota?
Jwan622

Risposte:


86

Puoi usare fixture_file_upload

include ActionDispatch::TestProcess nel tuo assistente di test, ecco un esempio di fabbrica:

include ActionDispatch::TestProcess

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

Nell'esempio precedente, spec/photos/test.pngdeve esistere nella directory principale dell'applicazione prima di eseguire i test.

Nota, questo FactoryBotè un nuovo nome per FactoryGirl.


2
Questa risposta è totalmente corretta, ma potrebbe essere più chiaro dire che TestProcess include deve essere incluso con Factory e non semplicemente nel tuo spec_helper.
Andrew Hubbs

2
Grazie per il chiarimento, Andrew. Potrebbe anche essere necessario inserire "include ActionDispatch :: TestProcess" prima del blocco FactoryGirl.define (che non è ciò che accade in questo gist: gist.github.com/313121 ).
Sam

3
Inoltre, { }sono obbligatori. Si rompe senza di essa
bigpotato

3
Ulteriore chiarimento: il include ActionDispatch::TestProcessdeve essere inserito all'inizio del file di fabbrica, fuori dal FactoryGirl.define do...endblocco.
Frank Koehl

49

Sintassi FG più recente e nessuna inclusione necessaria

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

o, meglio ancora,

factory :user do
  avatar { File.new("#{Rails.root}/spec/support/fixtures/image.jpg") } 
end

2
Mi piace, ma tieni presente che rails 4 rimuove app / assets / images / rails.png, quindi dovrai tenere conto di tale modifica :)
stephenmurdoch

38

Desmond Bowe di Pivotal Labs suggerisce di evitare fixture_file_upload a causa di problemi di perdita di memoria. Invece, dovresti impostare i campi della graffetta direttamente nella tua fabbrica:

factory :attachment do
  supporting_documentation_file_name { 'test.pdf' }
  supporting_documentation_content_type { 'application/pdf' }
  supporting_documentation_file_size { 1024 }
  # ...
end

Per me va bene. Anche abbastanza semplice da non richiedere un file esistente nella cartella spec / test.
bibstha

2
Oltre a evitare perdite di memoria, in questo modo i test saranno più veloci.
evedovelli

Il post del blog citato è stato spostato su pivotal.io/blog
Karsten S.

Sfortunatamente questo non funziona con la convalida degli allegati attiva content_type. Per questo è necessario un oggetto file valido.
Karsten S.



4

Prova a utilizzare ActionController :: TestUploadedFile. Puoi semplicemente impostare la proprietà file su un'istanza di TestUploadedFile e paperclip dovrebbe occuparsi del resto. Per esempio

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

0

Le risposte di cui sopra in alcuni casi possono aiutare, e quella in realtà ha aiutato in una delle mie situazioni, ma quando si utilizza un Carrierwave, la soluzione precedente di questa domanda non ha funzionato questa volta.

PRIMO APPROCCIO:

Per me l'aggiunta di un after :createrisolto il problema per me in questo modo:

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

L'impostazione del file video in linea come video_file { File.new("#{Rails.root}/spec/fixtures/sample.mp4") }non ha funzionato e riportava errori.

SECONDO APPROCCIO:

Definisci una fabbrica come questa (change personal_file il nome del tuo allegato):

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

E aggiungi queste righe a config/environemnts/test.rb:

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

-1

Cosa stai testando esattamente? Quella graffetta allegherà correttamente il file? Sembra davvero un test che la graffetta dovrebbe gestire, non la tua applicazione.

Hai provato

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

Usiamo Machinist invece di factory_girl e abbiamo appena usato cose come

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

Tuttavia, non stiamo davvero testando molto quando lo facciamo, in genere vogliamo solo avere un Imageoggetto valido .


Ho modelli che richiedono un'associazione valida con un modello abilitato per Paperclip, a sua volta con un allegato valido.
Eric,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.