Тестирование действий контроллера с учетом ожиданий с проверкой изменений в количестве при использовании `let`

#ruby-on-rails #ruby #ruby-on-rails-4 #rspec #controller

#ruby-on-rails #ruby #ruby-on-rails-4 #rspec #контроллер

Вопрос:

Я нахожусь в процессе рефакторинга некоторых спецификаций для использования let вместо переменных экземпляра.

Я столкнулся с проблемой со спецификацией контроллера:

 describe "#destroy" do

    let(:gallery){ create(:gallery) }

    context "when not authenticated" do

      it {
        expect{
          delete :destroy, id: gallery
        }.to_not change{ Gallery.count }
        should redirect_to new_user_session_path
      }

    end
end
  

Похоже, что проблема возникает из-за использования ‘let because it lazy-creates gallery the first time it is referenced which in this case is inside the expect block. So the Gallery.count` на самом деле увеличивается с 0 до 1, что приводит к сбою теста. На данный момент тест завершается неудачно из-за реализации RSpec, а не из-за кода, который он тестирует.

Очевидно, я мог бы вернуться к созданию камбуза в before блоке и сохранить его в переменной экземпляра, но это кажется немного хакерским. Обходной путь заключается в добавлении блока before, который ссылается на галерею, заставляя его оцениваться перед ожидаемым блоком:

 before { gallery }
  

Каков наилучший способ структурировать эту спецификацию?

Как я должен структурировать этот тест?

Ответ №1:

Не самый элегантный способ, но это работает для меня:

 describe "#destroy" do

  let(:gallery){ create(:gallery) }

  context "when not authenticated" do

    it {
      gallery
      expect{
        delete :destroy, id: gallery
      }.to_not change{ Gallery.count }
      should redirect_to new_user_session_path
    }

  end
end
  

Если вы не меняете значение gallery между тестами в группе, то на самом деле нет необходимости использовать let () в первую очередь, поэтому вы можете просто выполнить блок before, как вы упомянули, и он немного более читабелен:

 describe "#destroy" do

  context "when not authenticated" do

    before { @gallery = create(:gallery) }

    it {
      expect{
        delete :destroy, id: @gallery
      }.to_not change{ Gallery.count }
      should redirect_to new_user_session_path
    }

  end
end