J'essaie de renforcer ma compréhension de Rails et du flux de travail BDD. Je voulais donc commencer modestement en créant l'un de ces mini-blogs, mais avec rspec. À l'heure actuelle, j'ai un modèle ArticlesController et Article, ainsi que les fichiers rspec associés. L'article est très simple, il a juste pour titre: chaîne et contenu: texte, et ArticlesController est RESTful - bien que j'aie écrit à la main le MCV pour Article, c'est fondamentalement la même chose que si je l'utilisais pour le créer.
Cependant, je ne sais pas vraiment ce que je fais quand il s’agit d’écrire un test dans rspec pour la mise à jour de PUT. J'utilise Factory Girl pour créer l'objet article, et jusqu'à présent, mon code ressemble à ceci:
#factories.rb
FactoryGirl.define do
factory :article do
title "a title"
content "hello world"
end
#articles_controller_spec.rb
before(:each) do
@article = Factory(:article)
end
describe "PUT 'update/:id'" do
it "allows an article to be updated" do
@attr = { :title => "new title", :content => "new content" }
put :update, :id => @article.id, :article => @attr
response.should be_successful
end
end
Cependant je continue à recevoir:
Failures:
1) ArticlesController PUT 'update/:id' allows an article to be updated
Failure/Error: response.should be_successful
expected successful? to return true, got false
Qu'est-ce que je fais mal? Et est-ce que j'utilise les bons outils? Lorsque j'exécute mon serveur de test, Nouveau, Modifier, Détruire, tout fonctionne comme prévu, donc je suppose que c'est un problème de compréhension de RSpec. Faites-moi savoir si je me trompe - merci!
Vous avez oublié de .reload
votre @article
et sur l'action update
votre réponse effectue probablement la redirection
RSpec 2:
describe "PUT update/:id" do
let(:attr) do
{ :title => 'new title', :content => 'new content' }
end
before(:each) do
put :update, :id => @article.id, :article => attr
@article.reload
end
it { response.should redirect_to(@article) }
it { @article.title.should eql attr[:title] }
it { @article.content.should eql attr[:content] }
end
Rspec 3:
describe "PUT update/:id" do
let(:attr) do
{ :title => 'new title', :content => 'new content' }
end
before(:each) do
put :update, :id => @article.id, :article => attr
@article.reload
end
it { expect(response).to redirect_to(@article) }
it { expect(@article.title).to eql attr[:title] }
it { expect(@article.content).to eql attr[:content] }
end
Lorsque vous faites un PUT :update
, rappelez-vous que vous modifiez un modèle existant, que vous devez appeler dans la variable put
. Passez juste votre @article
et mettez à jour les attributs comme suit.
describe "PUT 'update/:id'" do
it "allows an article to be updated" do
put :update, :id => @article.id, :article => @article.attributes = { :title => "new title", :content => "new content" }
response.should be_successful
end
end
FactoryGirl.define :article do
title "a title"
content "hello world"
end
before(:each) do
@article = Factory(:article)
end
it "should re-render edit template on failed update" do
@attr = { :title => "", :content => "new content" }
put :update, :id => @article.id, :article => @attr
flash[:notice].should be_nil
response.should render_template('edit')
end
it "should redirect to index with a notice on successful update" do
@attr = { :title => "new title", :content => "new content" }
put :update, :id => @article.id, :article => @attr
assigns[:article].should_not be_new_record
flash[:notice].should_not be_nil
response.should redirect_to(:action => 'index')
end
Pour tester la méthode de mise à jour, j'aime bien vérifier que le temps updated_at est supérieur à ce qu'il était auparavant. Lorsque vous faites cela, vous pouvez modifier le contenu de la variable d'instance entière et toujours vérifier si tout a été mis à jour. Par exemple:
describe "PUT 'update/:id'" do
it "allows an article to be updated" do
prev_updated_at = @article.updated_at
@attr = { :title => "new title", :content => "new content" }
put :update, :id => @article.id, :article => @attr
@article.reload
@article.updated_at.should != prev_updated_at
end
end