rspec 使用活动记录悲观锁定时更改预期失败

rspec change expectation fails when using active record pessimistic locking

我有一个 Rails 4.2.0 方法,它使用悲观锁定来更改计数器

class Foo < < ActiveRecord::Base
  def bump!
    transaction do
      lock!
      parent.lock!

      lock.counter += 1
      parent.counter += 1

      save!
      parent.save!
    end
  end
end

我正在使用Rspec 3.1来测试它

expect{foo.bump!}.to change(foo, :counter).by(1)
expect{foo.bump!}.to change(foo.parent, :counter).by(1)

第一个 change(foo, :counter) 测试通过但第二个 change(foo.parent, :counter) 失败,除非我同时注释掉 lock!parent.lock!

如果我像这样重写失败的测试,它就会通过

prev_counter = foo.parent.counter
foo.bump!
expect(foo.parent.counter).to eq prev_counter + 1

为什么它不适用于 expect{...}.to change

您的问题是 RSpec 测试中的 foo.parent 实例与您的 Foo#bump! 方法正在修改的 parent 实例不同,因为调用 parent.lock! reloads the parent association to get the lock and thus you modify a different instance than rspec has bound its own lambda to。最简单的修复是使用 change { } 语法,它不会将接收者实例绑定到 foo.parent,而是仅绑定到 foo,它不会改变,如下所示:

expect{foo.bump!}.to change{foo.counter}.by(1)
expect{foo.bump!}.to change{foo.parent.counter}.by(1)

这个修复在本地对我有效。