首页 文章

Rspec :: Matcher 'change'方法,带接收器和消息与块

提问于
浏览
2

我正在尝试测试删除关联 . 涉及的两个模型是 UserCancellation

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

谁能解释我是否正确?为何这些不同的行为?

1 回答

  • 2

    在第一种形式中, cancellation.reload 被计算一次,结果对象在调用 click_link 方法之前和之后发送了消息 taker . 换句话说,在调用 click_link 之后,不会重新加载 cancellation 对象 .

    在第二种形式中, cancellation.reload.taker 在调用 click_link 之前和之后被完整地评估,因此 reload 有机会在数据库更新发生后生效 .

    但请注意,根据您的配置,处理 click_link 结果的服务器可能在单独的线程中执行,因此无论如何在数据库更新和测试断言之间存在竞争条件 .

相关问题