Метод за промяна на Rspec::Matcher с приемник и съобщение срещу блок

Опитвам се да тествам изтриването на асоциация. Двата включени модела са User и Cancellation:

    class Cancellation < Active Record::Base
      belongs_to :taker, class_name: "User"
    end

    class User < ActiveRecord::Base
      has_many :taken_cancellations, class_name: "Cancellation", foreign_key: :taker_id
    end

В моя тест имам следния код:

describe "Admin Calendar" do
  subject { page } 

  let!(:user) { FactoryGirl.create(:user, name: "Taker User") }
  let(:cancellation) { FactoryGirl.create(:cancellation, start_at: 2.days.from_now, taker: user) }

  before do
    sign_in admin
    visit edit_admin_cancellation_path cancellation
  end

  #...

  describe "Edit Page" do
    it 'Making it available' do
      expect { click_link "Make it available" }.to change(cancellation.reload, :taker).from(user).to nil
    end
  end
end

click_link 'Make it available ще задейства user.taken_cancellations.delete @cancellation в контролера.

Тестът е неуспешен с тази грешка:

taker should have been changed to nil, but is now #<User id: 1, name: "Taker User"...

от ръководствата за метода let: https://relishapp.com/rspec/rspec-core/v/2-6/docs/helper-methods/let-and-let

Стойността ще се кешира в множество извиквания в един и същ пример, но не и в примери.

За мен изглежда, че методът change създава нов cancellation след действието, вместо да разглежда мемоизирания. Не очаквах това поведение.

Тестът преминава при използване на блок, така:

expect { click_link "Make it available" }.to change { cancellation.reload.taker }.from(user).to nil

Може ли някой да обясни дали съм прав? Защо тези различни поведения?


person felix    schedule 26.01.2015    source източник


Отговори (1)


В първата форма cancellation.reload се оценява веднъж и полученият обект изпраща съобщението taker преди и след извикването на метода click_link. С други думи, обектът cancellation не се презарежда след извикването на click_link.

Във втората форма cancellation.reload.taker се оценява в своята цялост преди и след извикването на click_link, така че reload има шанс да влезе в сила след извършване на актуализацията на базата данни.

Обърнете внимание обаче, че в зависимост от вашата конфигурация, сървърът, който обработва резултата от click_link, може да се изпълнява в отделна нишка, така че във всеки случай има условие за надпревара между актуализацията на базата данни и тестовото твърдение.

person Peter Alfvin    schedule 28.01.2015
comment
Има смисъл. Благодаря ти! - person felix; 28.01.2015