web-dev-qa-db-fra.com

Comment écrire un test RSpec pour une simple mise à jour de PUT?

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!

31
oort

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
55
Rustam A. Gasanov

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
6
nmott
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
1
Sandip Ransing

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
0
David Hahn