Как написать RSpec-тест для простого обновления PUT?
Я пытаюсь укрепить свое понимание рельсов и рабочего процесса BDD, поэтому я хотел начать с малого, создав один из этих мини-блогов, но с rspec. Сейчас у меня есть модель ArticleController и Article, а также связанные с ней файлы rspec. Статья очень проста, имеет только название: строка и контент: текст, а ArticlesController - RESTful - хотя я вручную написал MCV для статьи, он в основном такой же, как если бы я использовал эшафот для его создания.
Однако я не знаю, что я делаю, когда дело доходит до написания теста в rspec для обновления PUT. Я использую Factory Girl для создания объекта статьи, и до сих пор мой код выглядит следующим образом:
#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
Однако я продолжаю получать:
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
Что я делаю неправильно? И использую ли я правильные инструменты? Когда я запускаю свой тестовый сервер, New, Edit, Destroy, все работают так, как я ожидал бы, поэтому я предполагаю, что это проблема с моим пониманием RSpec. Дайте мне знать, если я ошибаюсь - спасибо!
Ответы
Ответ 1
Вы забыли .reload
ваш @article
, а при действии update
ваш ответ скорее всего выполнит перенаправление, поэтому
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
Ответ 2
Когда вы делаете PUT :update
, помните, что вы редактируете существующую модель, которую нужно вызвать в put
. Просто передайте @article
и обновите атрибуты следующим образом.
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
Ответ 3
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
Ответ 4
Как мне нравится тестировать метод обновления, просто убедитесь, что время update_at больше, чем было раньше. Когда вы это сделаете, вы можете изменить содержимое всей переменной экземпляра и по-прежнему проверить, обновлено ли все. Например:
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