Jak wykorzystać Factory Girl do wygenerowania spinacza?

119

Mam model Person, który ma wiele obrazów, w których obrazy mają pole załącznika Spinacz o nazwie dane, skróconą wersję wyświetlaną poniżej:

class Person
  has_many :images
  ...
end

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

Osoba musi mieć dołączony co najmniej jeden obraz.

Korzystając z FactoryGirl, mam kod podobny do następującego:

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

(Uwaga: wypróbowałem również kod skomentowany powyżej). W większości przypadków, gdy uruchamiam funkcje ogórka, pojawia się błąd podobny do następującego:

Brak takiego pliku lub katalogu - /tmp/stream,9887,0.png (Errno :: ENOENT)

...

Czasami testy przebiegają pomyślnie.

Czy ktoś może mi powiedzieć, jaki mam tutaj problem lub w jaki sposób używają razem FactoryGirl i Paperclip, aby osiągnąć coś takiego, co próbuję osiągnąć?

Używam Rails 3.

Laz
źródło
2
Głosuj pozytywnie na pytanie tylko za używanie Keyzer Soze podczas testowania nazwy!
Breno
Kiedy to robię ... zdjęcia są generowane i umieszczane w folderze publicznym / systemowym za każdym razem, gdy uruchamiam pakiet testów. Zdjęcia nie są niszczone po uruchomieniu zestawu testów. Czy ktoś jeszcze to zauważył?
Jwan622,

Odpowiedzi:

86

Możesz użyć fixture_file_upload

include ActionDispatch::TestProcess w twoim pomocniku testowym, oto przykładowa fabryka:

include ActionDispatch::TestProcess

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

W powyższym przykładzie spec/photos/test.pngmusi istnieć w katalogu głównym aplikacji przed uruchomieniem testów.

Uwaga, FactoryBotto nowa nazwa dla FactoryGirl.

DanS
źródło
2
Ta odpowiedź jest całkowicie prawidłowa, ale może być bardziej jasne, że można powiedzieć, że proces testowy musi być dołączony do fabryki, a nie tylko do pomocy spec_helper.
Andrew Hubbs,
2
Dzięki za wyjaśnienie, Andrew. Może być również konieczne umieszczenie „include ActionDispatch :: TestProcess” przed blokiem FactoryGirl.define (co nie jest tym, co dzieje się w tym streszczeniu : gist.github.com/313121 ).
Sam
3
Ponadto { }są wymagane. Bez tego się
psuje
3
Dalsze Wyjaśnienie: include ActionDispatch::TestProcessnależy umieścić na samym początku pliku fabrycznego, poza tym FactoryGirl.define do...endbloku.
Frank Koehl
49

Nowsza składnia FG i brak konieczności dołączania

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

Lub jeszcze lepiej,

factory :user do
  avatar { File.new("#{Rails.root}/spec/support/fixtures/image.jpg") } 
end
Neal
źródło
2
Podoba mi się, ale pamiętaj, że rails 4 usuwa app / asset / images / rails.png, więc trzeba będzie uwzględnić tę zmianę :)
Stephenmurdoch
38

Desmond Bowe z Pivotal Labs sugeruje unikanie fixture_file_upload z powodu problemów z wyciekiem pamięci. Zamiast tego powinieneś ustawić pola spinaczy bezpośrednio w swojej fabryce:

factory :attachment do
  supporting_documentation_file_name { 'test.pdf' }
  supporting_documentation_content_type { 'application/pdf' }
  supporting_documentation_file_size { 1024 }
  # ...
end
Rick Quantz
źródło
Pracuje dla mnie. Również na tyle proste, że nie wymaga istniejącego pliku w folderze spec / test.
bibstha
2
Oprócz unikania wycieków pamięci w ten sposób testy będą szybsze.
evedovelli
Wspomniany wpis na blogu został przeniesiony do pivotal.io/blog
Karsten S.
Niestety nie działa to z włączoną weryfikacją załączników content_type. Do tego potrzebny jest prawidłowy obiekt pliku.
Karsten S.
25

Użyłem kodu w istocie poniżej:

Szyny 2

http://gist.github.com/162881

Szyny 3

https://gist.github.com/313121

deb
źródło
1
Po prostu zastanawiam się nad tym samym i to działa pięknie. Dzięki. Umieściłem to w inicjatorze.
Todd
1
Coś do zapamiętania: w powyższym streszczeniu użyto starszej składni FactoryGirl. Odpowiedź DanS używa nowej składni.
Andrew Hubbs,
12
file { File.new(Rails.root.join('spec', 'fixtures', 'filename.png')) }
Matthew Deiters
źródło
To najprostsze rozwiązanie funkcjonalne.
superluminary
4

Spróbuj użyć ActionController :: TestUploadedFile. Możesz po prostu ustawić właściwość file na instancję TestUploadedFile, a spinacz powinien zająć się resztą. Na przykład

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
źródło
0

Powyższe odpowiedzi w niektórych przypadkach mogą pomóc, a ta faktycznie pomogła w jednej z moich sytuacji, ale podczas korzystania z Carrierwave poprzednie rozwiązanie z tego pytania tym razem nie zadziałało.

PIERWSZE PODEJŚCIE:

U mnie dodanie after :createrozwiązanego problemu u mnie w ten sposób:

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

Ustawienie wbudowanego pliku wideo video_file { File.new("#{Rails.root}/spec/fixtures/sample.mp4") }nie zadziałało i zgłaszało błędy.

DRUGIE PODEJŚCIE:

Zdefiniuj taką fabrykę (zmień personal_filenazwę załącznika):

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

I dodaj te wiersze do config/environemnts/test.rb:

config.paperclip_defaults = {
  url: "#{Rails.root}/spec/fixtures/:attachment/:filename",
  use_timestamp: false
}
Aleks
źródło
-1

Co dokładnie testujesz? Czy spinacz z powodzeniem załączy plik? To naprawdę wygląda na test, który powinien obsługiwać spinacz, a nie na twoją aplikację.

Czy próbowałeś

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

Używamy Machinist zamiast factory_girl i używamy takich rzeczy jak

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

Chociaż tak naprawdę nie testujemy zbyt wiele, kiedy to robimy, zazwyczaj chcemy mieć tylko prawidłowy Imageobiekt.

theIV
źródło
Mam modele, które wymagają prawidłowego skojarzenia z modelem obsługującym spinacz, sam z prawidłowym załącznikiem.
Eric