2011-01-14 6 views
4

Starten Sie einfach mit RSpec. Alles läuft reibungslos, außer einer Spezifikation mit verschachtelten Controllern.RSpec Neuling: "Update-Attribute => False" wird nicht erkannt

Ich versuche sicherzustellen, dass, wenn eine 'Kommentar' Ressource (verschachtelt unter 'Post') mit ungültigen Parametern aktualisiert wird, es die Vorlage 'Bearbeiten' rendert. Ich bemühe mich, rspec zu bekommen, um den: update_attributes => false trigger zu erkennen. Wenn jemand irgendwelche Vorschläge hat, würden sie sehr geschätzt werden. Versuchte Code unten:

def mock_comment(stubs={}) 
    stubs[:post] = return_post 
    stubs[:user] = return_user 
    @mock_comment ||= mock_model(Comment, stubs).as_null_object 
    end 

    describe "with invalid paramters" dog 
    it "re-renders the 'edit' template" do 
     Comment.stub(:find).with("12") { mock_comment(:update_attributes => false) } 
     put :update, :post_id => mock_comment.post.id, :id => "12" 
     response.should render_template("edit") 
    end 
    end 

Und der Controller:

def update 
    @comment = Comment.find(params[:id]) 
    respond_to do |format| 
     if @comment.update_attributes(params[:comment]) 
     flash[:notice] = 'Post successfully updated' 
     format.html { redirect_to(@comment.post) } 
     format.xml { head :ok } 
     else 
     format.html { render :action => "edit" } 
     format.xml { render :xml => @comment.errors, :status => :unprocessable_entity } 
     end 
    end 

    end 

Und schließlich der Fehler:

Failure/Error: response.should render_template("edit") 
    expecting <"edit"> but rendering with <"">. 
    Expected block to return true value. 

Antwort

5

Dies ist ein recht interessantes Problem. Eine schnelle Lösung ist es, die Blockform Comment.stub einfach zu ersetzen:

Comment.stub(:find).with("12") { mock_comment(:update_attributes => false) } 

mit einer expliziten and_return:

Comment.stub(:find).with("12").\ 
    and_return(mock_comment(:update_attributes => false)) 

Wie, warum diese beiden Formen zu unterschiedlichen Ergebnissen führen sollte, das ist ein bisschen ein Kopf- Kratzer. Wenn Sie mit dem ersten Formular herumspielen, werden Sie sehen, dass der Schein tatsächlich self anstelle von false zurückgibt, wenn die Stubbed-Methode aufgerufen wird. Das sagt uns, dass es die Methode nicht abgestempelt hat (da es als ein Null-Objekt spezifiziert ist).

Die Antwort ist, dass der Block beim Übergeben eines Blocks nur ausgeführt wird, wenn die Stubbed-Methode aufgerufen wird, nicht wenn der Stub definiert ist. So bei der Verwendung der Blockform den folgenden Aufruf:

put :update, :post_id => mock_comment.post.id, :id => "12" 

ausführt mock_comment zum ersten Mal. Da :update_attributes => false nicht übergeben wird, wird die Methode nicht stubbed, und der Schein wird zurückgegeben, anstatt false. Wenn der Block mock_comment aufruft, gibt er @mock_comment zurück, das den Stub nicht hat.

Umgekehrt ruft das explizite Formular and_return sofort mock_comment auf. Es wäre wahrscheinlich besser, die Instanzvariable zu verwenden, anstatt die Methode jedes Mal aufzurufen, um die Absicht klarer zu machen:

+0

Hervorragende, gründliche, klare Antwort. Danke vielmals. :-) – PlankTon