Wie teste ich einen Datei-Upload in Rails?

101

Ich habe einen Controller, der dafür verantwortlich ist, JSON-Dateien zu akzeptieren und dann die JSON-Dateien zu verarbeiten, um einige Benutzerwartungen für unsere Anwendung durchzuführen. Beim Benutzertest funktioniert das Hochladen und Verarbeiten von Dateien, aber natürlich möchte ich den Testprozess der Benutzerwartung in unseren Tests automatisieren. Wie kann ich eine Datei auf einen Controller im Framework für Funktionstests hochladen?

Tier
quelle

Antworten:

110

Ich habe nach dieser Frage gesucht und konnte sie oder ihre Antwort auf Stack Overflow nicht finden, habe sie aber an anderer Stelle gefunden. Deshalb bitte ich sie, sie auf SO verfügbar zu machen.

Das Rails-Framework verfügt über eine Funktion fixture_file_upload( Rails 2 Rails 3 , Rails 5 ), die Ihr Fixtures-Verzeichnis nach der angegebenen Datei durchsucht und diese als Testdatei für den Controller beim Funktionstest zur Verfügung stellt. Um es zu benutzen:

1) Fügen Sie Ihre hochzuladende Datei zum Testen in das Unterverzeichnis Ihrer Geräte / Dateien zum Testen ein.

2) In Ihrem Unit-Test können Sie Ihre Testdatei abrufen, indem Sie fixture_file_upload ('path', 'mime-type') aufrufen.

z.B:

bulk_json = fixture_file_upload('files/bulk_bookmark.json','application/json')

3) Rufen Sie die post-Methode auf, um die gewünschte Controller-Aktion auszuführen, und übergeben Sie das von fixture_file_upload zurückgegebene Objekt als Parameter für den Upload.

z.B:

post :bookmark, :bulkfile => bulk_json

Oder in Rails 5: post :bookmark, params: {bulkfile: bulk_json}

Dies durchläuft den simulierten Post-Prozess mit einer Tempfile-Kopie der Datei in Ihrem Fixtures-Verzeichnis und kehrt dann zu Ihrem Komponententest zurück, damit Sie mit der Prüfung der Ergebnisse des Posts beginnen können.

Tier
quelle
2
Dies funktioniert nicht auf Schienen 3. Die Datei action_controller / test_process ist anscheinend nicht in activesupport 3 verfügbar. Ich habe eine neue Frage für das gleiche hier geöffnet
stackoverflow.com/questions/3966263/…
Der Link in Ihrer Antwort lautet 404, oder ist es nur für mich?
Ernest
@Chirantan es ist zu ActionDispatch :: TestProcess verschoben
ben Autor
Wie kann dies mit FactoryGirl verwendet werden? stackoverflow.com/questions/34677780/…
Richlewis
85

Moris Antwort ist richtig, außer dass Sie in Rails 3 anstelle von "ActionController :: TestUploadedFile.new" "Rack :: Test :: UploadedFile.new" verwenden müssen.

Das erstellte Dateiobjekt kann dann als Parameterwert in Rspec- oder TestUnit-Tests verwendet werden.

test "image upload" do
  test_image = path-to-fixtures-image + "/Test.jpg"
  file = Rack::Test::UploadedFile.new(test_image, "image/jpeg")
  post "/create", :user => { :avatar => file }
  # assert desired results
  post "/create", :user => { :avatar => file }     

  assert_response 201
  assert_response :success
end
Victor Gray
quelle
Diese Methode ist eine gute Alternative, wenn sich Ihre Geräte nicht in / test / fixtures befinden. Wenn Sie beispielsweise einige Dateien für die Tests dynamisch generieren, befinden sie sich möglicherweise stattdessen in einem Ordner / tmp.
Olivier Amblet
25

Ich denke, es ist besser, das neue ActionDispatch :: Http :: UploadedFile folgendermaßen zu verwenden:

uploaded_file = ActionDispatch::Http::UploadedFile.new({
    :tempfile => File.new(Rails.root.join("test/fixtures/files/test.jpg"))
})
assert model.valid?

Auf diese Weise können Sie dieselben Methoden verwenden, die Sie in Ihren Validierungen verwenden (z. B. tempfile).

David Morales
quelle
8

Aus dem Rspec-Buch, B13.0:

Rails 'bietet eine ActionController :: TestUploadedFile-Klasse, mit der eine hochgeladene Datei im Parameter-Hash einer Controller-Spezifikation dargestellt werden kann:

describe UsersController, "POST create" do
  after do
    # if files are stored on the file system
    # be sure to clean them up
  end

  it "should be able to upload a user's avatar image" do
    image = fixture_path + "/test_avatar.png"
    file = ActionController::TestUploadedFile.new image, "image/png"
    post :create, :user => { :avatar => file }
    User.last.avatar.original_filename.should == "test_avatar.png"
  end
end

Diese Spezifikation würde erfordern, dass Sie ein test_avatar.png-Image im Verzeichnis spec / fixtures haben. Es würde diese Datei nehmen, sie auf den Controller hochladen und der Controller würde ein echtes Benutzermodell erstellen und speichern.

Mori
quelle
2
Beim Ausführen eines Tests mit diesem Code wird der Fehler "Nicht initialisierte Konstante ActionController :: TestUploadedFile" angezeigt. Sonst noch etwas, das ich in der Datei benötigen würde?
Vini.g.fer
1
Es scheint bereits in Rails 2.3 veraltet zu sein. Für Rails 3.0 ab, hier ist , wie Sie es tun mit Geräten
Sebastialonso
1

Wenn Sie Standardschienen verwenden, testen Sie mit Factory Girl. Gut unter dem Code.

factory :image_100_100 do
    image File.new(File.join(::Rails.root.to_s, "/test/images", "100_100.jpg"))
end

Hinweis: Sie müssen ein Dummy-Bild behalten /test/images/100_100.jpg.

Es funktioniert perfekt.

Prost!

Manish Shrivastava
quelle
0

Wenn Sie die Datei in Ihrem Controller wie folgt erhalten

json_file = params[:json_file]
FileUtils.mv(json_file.tempfile, File.expand_path('.')+'/tmp/newfile.json')

Versuchen Sie dann Folgendes in Ihren Spezifikationen:

json_file = mock('JsonFile')
json_file.should_receive(:tempfile).and_return("files/bulk_bookmark.json")
post 'import', :json_file => json_file
response.should be_success

Dadurch wird die gefälschte Methode zur 'tempfile'-Methode, die den Pfad zur geladenen Datei zurückgibt.

Esenbek Kydyr uulu
quelle