#ruby-on-rails #rspec
#ruby-on-rails #rspec
Вопрос:
Новичок в RSpec и у меня возникли проблемы с отключением метода обновления (необходимо отключить), и я столкнулся с этой ошибкой. Я перепробовал кучу разных способов и, похоже, не могу это решить. Я попытался включить только необходимый код.
/spec/controllers/admin/business_controller_spec.rb
:
require 'spec_helper'
RSpec.describe Admin::BusinessesController, type: :controller do
render_views
before(:all) do
@business = build_stubbed(:business)
end
describe '#update' do
before(:each) do
allow(Business).to receive(:find).and_return(@business)
@new_name = Faker::Company.name
@params = { id: @business.id, business: { name: @new_name } }
end
it 'updates business name' do
expect(@business).to receive(:update_attributes).with(name: @new_name, confirm_flag: @business.confirm_flag, phone_primary: @business.phone_primary).and_return(true)
xhr :patch, :update, id: @business.id, business: { name: @new_name }
expect(@business.name).to eq(@new_name)
end
end
end
/app/controllers/admin/businesses_controller.rb
class Admin::BusinessesController < Admin::BaseAdminController
def update
@business.update_attributes(business_params)
end
def business_params
params.require(:business).permit(:name, :active_flag).merge(confirm_flag: true, phone_primary: '')
end
end
Когда я запускаю этот тест, я получаю эту ошибку:
Failures:
1) Admin::BusinessesController#update updates business name
Failure/Error: @business.update_attributes(business_params)
#<Business:0x007fc43c4f5738> received :update_attributes with unexpected arguments
expected: ({:name=>"Fadel, Larson and Hettinger", :confirm_flag=>true, :phone_primary=>"7832900175"})
got: ({"name"=>"Fadel, Larson and Hettinger", "confirm_flag"=>true, "phone_primary"=>""})
Diff:
@@ -1,4 1,4 @@
-[{:name=>"Fadel, Larson and Hettinger",
- :confirm_flag=>true,
- :phone_primary=>"7832900175"}]
[{"name"=>"Fadel, Larson and Hettinger",
"confirm_flag"=>true,
"phone_primary"=>""}]
Похоже phone_primary
, что это вызывает проблему, и я меняю свою строку ожидания теста на:
describe '#update' do
before(:each) do
allow(Business).to receive(:find).and_return(@business)
@new_name = Faker::Company.name
@params = { id: @business.id, business: { name: @new_name } }
end
it 'updates business name' do
expect(@business).to receive(:update_attributes).with(name: @new_name, confirm_flag: @business.confirm_flag, **phone_primary: ''**).and_return(true)
xhr :patch, :update, id: @business.id, business: { name: @new_name }
expect(@business.name).to eq(@new_name)
end
end
и я получаю сбой:
Failures:
1) Admin::BusinessesController#update updates business name
Failure/Error: expect(@business.name).to eq(@new_name)
expected: "Flatley Inc"
got: "Samara Kuhic"
И теперь имена не совпадают
Комментарии:
1. Добавьте
.and_call_original
к вашей заглушкеupdate_attributes
. Правильно, он не выполняет никаких обновлений, и ваши последующие ожидания, естественно, терпят неудачу.2. я заглушаю .. специально не попадая в базу данных
3. Видите ли, когда вы заглушаете метод ( специально !), Вы также не можете ожидать, что он выполнит свою работу. Потому что вы его заглушили. Есть пирог и есть его тоже.
4. @SergioTulentsev так что, нет способа отключить метод обновления в RSpec?
5. Есть способ, вы это делаете. Как я уже говорил, вы не можете съесть торт и съесть его. Вы должны выбрать, какой из них вы хотите.
Ответ №1:
В итоге я остановил перезагрузку с помощью назначений. Мои тесты сейчас проходят с этим:
describe '#update' do
before(:each) do
allow(Business).to receive(:find).and_return(@business)
@new_name = Faker::Company.name
end
it 'updates business name' do
expect(@business).to receive(:update_attributes).with(name: @new_name, confirm_flag: true, phone_primary: '').and_return(@business)
xhr :patch, :update, id: @business.id, business: { name: @new_name }
expect(assigns(:business)).to eq(@business)
expect(response.status).to eq(200)
end
end
Не уверен, что это предпочтительный способ, но он подходит для меня. Похоже assigns
, будет устаревшим в Rails 5
Комментарии:
1. Лично я никогда не беспокоюсь о тестах контроллера. Может быть, только для какой-то сложной логики маршрутизации. Проверки бизнес-логики либо переходят к спецификациям функций (где нет заглушки), либо к спецификациям модулей (неограниченная заглушка).
2. Спецификации контроллера находятся в этой странной промежуточной точке, Где вам нужно выполнить некоторые заглушки (для аутентификации и т. Д.), Но вы не хотите делать слишком много (иначе ваш тест становится оторванным от реальности).).
Ответ №2:
Если вы проверяете свой исходный код, в вашем контроллере у вас есть это:
def business_params
params.require(:business).permit(:name, :active_flag).merge(confirm_flag: true, phone_primary: '')
end
вы всегда устанавливаете confirm_flag
значение true
и phone_primary
значение ''
(пустая строка). И в вашем тесте у вас есть это:
expect(@business).to receive(:update_attributes).with(name: @new_name, confirm_flag: @business.confirm_flag, phone_primary: @business.phone_primary).and_return(true)
итак, если вы проверяете confirm_flag
, что вы устанавливаете его @business.confirm_flag
, что в данном случае на самом деле так и есть true
, и это нормально с тем, что вы устанавливаете в контроллере, но проблема возникает с phone_primary
тем, что устанавливается @business.phone_primary
, а в данном случае @business.phone_primary
есть 7832900175
, и именно поэтому он терпит неудачу.
Итак, чтобы исправить это, вам нужно либо изменить свой тест на:
expect(@business).to receive(:update_attributes).with(name: @new_name, confirm_flag: @business.confirm_flag, phone_primary: '').and_return(true)
или измените код вашего контроллера на permit
phone_primary
из параметров, что также исправит вашу ошибку.
Комментарии:
1. Если вы прочтете остальную часть моего вопроса, вы увидите, что я сменил основной телефон, и это не решило проблему, поскольку имя не обновляется в тесте
2. что это за **, которые вы используете
phone_primary
?3. кто-то уже дал вам комментарий о вашей другой ошибке, похоже, вы подумали, что эта ошибка относится к тому же тесту.
4. звезды должны были выделить изменение жирным шрифтом .. извините, что так выглядит. Ошибки относятся к той же спецификации, но были отредактированы, чтобы сделать вопрос более читаемым. я обновил
5. Я вижу, итак, похоже, что ваша запись была обновлена с новым именем, и это нормально, не так ли?, и ваша ожидаемая строка такова:
expect(@business.name).to eq(@new_name)
, которая сравнивает@business.name
(которая имеет предыдущее имя) с@new_name
новым именем. Итак, прежде чем сравнивать эти значения, просто перезагрузите объект из базы данных снова с@business.reload
помощью, таким образом@business
, он будет перезагружен с новым именем.