Как заглушить действие обновления RSpec?

#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 , он будет перезагружен с новым именем.