2016-07-25 22 views
1

I wie unten eine Löschfunktion in einem meiner Controller haben:einen rspec Test für Löschaktion in Controller Schreiben

before_action :set_form, only: [:show, :edit, :update, :destroy] 
def destroy 
    if @form.destroy 
      render json: @form, status: :ok 
     else 
      render json: @form.errors, status: :not_found 
     end 
    end 

private 

    def set_form 
    @form = Form.find(params[:id]) 
    end 

end 

habe ich zwei Fragen:

1) Ich bin der Rückkehr 404, wenn löschen wird nicht korrekt ausgeführt. Ist das ein vernünftiger Statuscode? Ich habe den gesamten 4XX-Statuscode untersucht, und das war sehr sinnvoll.

2) Ich bin mir nicht sicher, wie ich einen Test für render json: @form.errors, status: :not_found schreiben werde.

Unten ist das, was ich versucht:

context "Cannot delete the model" do 
    it "responds successfully with an HTTP 404 status code" do 
     delete :destroy, id: 100000 
     expect(response).to have_http_status(404) 
    end 
end 

Das Problem ist, dass ich eine Fehlermeldung erhalten dass ActiveRecord::RecordNotFound:Couldn't find Visa with 'id'=10000 statt delete Aktion tatsächlich ausfällt. Wie verspotten Sie, dass delete Aktion fehlschlägt?

Antwort

1

Dieser Fehler ist der gleiche Fehler, den Sie in der Entwicklung und sogar in der Produktion bekommen. Die Linie ...

@form = Form.find(params[:id]) 

Wird eine Ausnahme auslösen, wenn kein Form Datensatz mit der gelieferten ID gefunden wird.

auch wenn die @form nicht gefunden werden und Sie finden weiterhin einen Mechanismus, wird die @form.destroy noch nicht funktionieren, da es keine Methode ist destroy auf nil Objekte, und es gibt auch keine Methode errors auf nil Objekte.

Wenn Sie darauf bestehen, zerstören Methoden der Handhabung, wie Sie beschreiben, würden Sie so etwas wie ...

before_action :set_form, only: [:show, :edit, :update] #remove destroy 
def destroy 
    @form = Form.find_by(id: params[:id]) 
    if @form 
    @form.destroy 
    render json: @form, status: :ok 
    else 
    render json: 'record not found for delete', status: :not_found 
    end 
end 
+0

findet find_by immer noch 'ActiveRecord :: RecordNotFound'? – JoHksi

+0

Nein, 'find' wird ausgelöst,' find_by' gibt 'nil' zurück. –

+0

yep, was @ MichaelKohl sagt. Michaels Antwort ist gut, aber Sie müssen auf die Möglichkeit vorbereitet sein, dass in den meisten Ihrer CRUD-Methoden ein Null-Objekt empfangen wird: show', ': edit',': update' – SteveTurczyn

0

Ihre set_form Methode löst diesen Fehler tun müssen, haben Sie es dort zu fangen oder find_by_id verwenden in destroy.

def set_form 
    @form = Form.find(params[:id]) 
rescue ActiveRecord::RecordNotFound 
end 

Auf diese Weise @formnil in Ihrem if sein wird.

Was den HTTP-Statuscode angeht, könnten Sie die Verwendung von 422 in Erwägung ziehen.

+0

ist 'rescue ActiveRecord :: RecordNotFound' nur @ form als Null zurückgeben, wenn es nicht gefunden werden kann? Und ist das ein hacky Weg oder nicht? Ich bin noch nie auf dieses Thema gestoßen, daher würde ich gerne mehr über diesen Ansatz erfahren. – JoHksi

+0

Es rettet die Ausnahme und macht nichts (ein 'def' ist ein implizites' begin' für einen 'begin-rescue-end' Block). Instanzvariablen werden immer auf "Null" initialisiert. Ich wollte dir nur zeigen, wo das Problem liegt, du kannst natürlich auch in 'destroy' retten und das' render json: @ form.errors, status:: not_found'-Bit dorthin legen. –

+0

Dies wirft ein anderes Problem auf. Wie kann ich testen, wenn die 'destroy'-Aktion fehlschlägt? Wie stelle ich dieses Verhalten in rspec vor, um 'render json: @ form.errors, status:: not_found' zu testen? Und wird das Fehlerhandling sogar für die "Zerstörungs" -Funktion benötigt? – JoHksi

0

Schienen werden eine ActiveRecord::RecordNotFound auslösen, wenn Sie .find auf einen Datensatz mit einer ungültigen ID aufrufen. Dies ist ein sehr wünschenswertes Verhalten, da es einen netten Zwischenfall für den Fall bietet, wenn eine Ressource nicht gefunden werden kann.

Standardmäßig wird ein Header 404 - nicht gefunden gesendet. Für den HTML-Anforderungstyp wird auch eine Standardfehlerseite gesendet.

Eher das Problem ist, wie Sie es testen.

Wenn Sie die Schienen testen möchten wirft den Fehler:

context "Cannot delete the model" do 
    it "raises an error when the id is not valid" do 
    bypass_rescue 
    expect { delete :destroy, id: 100000 }.to raise_error(ActiveRecord::RecordNotFound) 
    expect(response).to have_http_status(404) 
    end 
end 

Wenn Sie jedoch, dass das Löschen des Modells aus einem anderen Grund nicht testen wollen (Datensatz gesperrt ist oder der Benutzer zum Beispiel nicht zugelassen) Sie sollte einen Datensatz in der Datenbank mit Fixtures oder Fabriken einrichten und eine gültige ID bereitstellen - Sie sollten auch den richtigen Antwortcode angeben (422 oder 401).

Zum Meckern des Löschfehlers können Sie allow_any_instance_of(SomeModel).to receive(:destroy).and_return(false) verwenden.

+0

Macht es Ihnen etwas aus, ein zusätzliches Beispiel für einen Test zu geben, der 'render json: @ form.errors, status:: not_found' behandelt? Sagen wir, ich habe ein einziges gültiges Modell gefunden. Die 'destroy' Funktion scheitert jedoch aus irgendeinem Grund und trifft die obige Zeile, die ich geschrieben habe. Wie teste ich diesen Fall in rspec? Zusätzlich bekomme ich 200, wenn ich deinem Beispieltest folge. Ich bekomme auch '200' von Ihrem Beispiel' allow_any_instance_of (SomeModel) .zu erhalten (: destroy) .and_return (false) '. – JoHksi

+0

Ich würde mich sehr freuen, wenn Sie meine obigen Fragen beantworten können! – JoHksi