ruby on rails 3 - matchers - RSpec Newbie: "Actualizar atributos=> falso" no se reconoce
rspec rails 5 (1)
Justo comenzando con RSpec. Todo va bien, a excepción de una especificación con controladores anidados.
Estoy tratando de asegurar que cuando un recurso de ''comentario'' (anidado bajo ''publicación'') se actualice con parámetros no válidos, presente la plantilla ''editar''. Estoy luchando para conseguir que rspec reconozca el activador: update_attributes => false. Si alguien tiene alguna sugerencia, sería muy apreciada. Intento de código a continuación:
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
Y el controlador:
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
Y finalmente, el error:
Failure/Error: response.should render_template("edit")
expecting <"edit"> but rendering with <"">.
Expected block to return true value.
Este es un problema bastante interesante. Una solución rápida es simplemente reemplazar la forma de bloque de Comment.stub
:
Comment.stub(:find).with("12") { mock_comment(:update_attributes => false) }
con un and_return
explícito:
Comment.stub(:find).with("12")./
and_return(mock_comment(:update_attributes => false))
En cuanto a por qué estas dos formas deben producir resultados diferentes, eso es un poco de un rasguño de cabeza. Si juegas con la primera forma, verás que el simulacro está regresando self
lugar de false
cuando se llama al método stubbed. Eso nos dice que no ha rechazado el método (ya que está especificado como un objeto nulo).
La respuesta es que al pasar en un bloque, el bloque solo se ejecuta cuando se llama al método stubbed, no cuando se define el stub. Entonces cuando usa el formulario de bloque, la siguiente llamada:
put :update, :post_id => mock_comment.post.id, :id => "12"
está ejecutando mock_comment
por primera vez. Dado que :update_attributes => false
no se transfiere, el método no se repite y se devuelve el simulacro en lugar de false
. Cuando el bloque invoca mock_comment
, devuelve @mock_comment
, que no tiene el stub.
Por el contrario, usar la forma explícita de and_return
invoca mock_comment
inmediatamente. Probablemente sería mejor usar la variable de instancia en lugar de llamar al método cada vez para aclarar el intento:
it "re-renders the ''edit'' template" do
mock_comment(:update_attributes => false)
Comment.stub(:find).with("12") { @mock_comment }
put :update, :post_id => @mock_comment.post.id, :id => "12"
response.should render_template("edit")
end