在rspec中重新加载activerecord对象会更新数据库记录,而不是从db重新加载对象

时间:2016-12-06 21:53:53

标签: ruby ruby-on-rails-4 activerecord rspec-rails rspec3

我正在将我的应用程序从Rails 4.0升级到4.1(在前往4.2的路上)并且让这样的测试失败:

describe "#restore_disabled_account" do
  let(:username) { 'username' }
  let(:email) { 'email@domain.com' }
  let(:m3_user) { create(:user, username: username,
                                   email: email,
                                archived: false,
                  propagate_in_test_mode: true) }
  let(:m2_user) { Maestro2::User.where(UserID: m3_user.id).first }

  before do
    m3_user.disable_account
  end

  it "unarchives the account" do
    m3_user.restore_disabled_account
    m3_user.reload
    expect(m3_user.archived).to be_falsey
  end
end

我已经验证数据库包含在此测试开始时具有预期属性的记录。在调试测试时,我在重载语句之前停止,我看到db记录已按预期更新(存档为false,其他属性按预期更新)。我还可以看到m3_user对象已使用相同的属性进行更新。当我前进运行重新加载步骤并查询数据库时,我可以看到记录已恢复到其原始状态,内存中的对象也是如此。然后测试失败,因为m3_user.archived为真。

有人可以告诉我为什么吗?我的套件中的所有测试都在开始升级之前通过。该应用程序目前使用的是Ruby 2.2.4,Rails 4.1.16,rspec 3.5.3和rspec-rails 3.5.2

作为参考,下面是两个User类方法调用:

def disable_account
  self.update_attributes(username: "disabled_#{id}_#{username}",
                            email: "disabled_#{id}_#{email}",
                         archived: true)
end

def restore_disabled_account
  self.update_attributes(username: username.gsub(/^disabled_#{id}_/, ''),
                            email: email.gsub(/^disabled_#{id}_/, ''),
                         archived: false)
end

1 个答案:

答案 0 :(得分:0)

简短回答:事实证明,ActiveRecord 4.1更改了reload方法以调用名为reset_changes的新私有方法。我的用户类也有一个reset_changes方法,因此我的方法覆盖了应该调用的内容。

答案很长:我看到的越多,我就越怀疑我的用户模型独有的东西。使用reload的其他测试按预期执行。然后我在User中遇到了reset_changes方法。看到它做了什么(用以前的值更新db记录)后,我将一个puts语句放入其中,以便我看看它是否被调用。一旦确认,我就抛弃了调用者回溯,它指向https://github.com/rails/rails/blob/4-1-stable/activerecord/lib/active_record/attribute_methods/dirty.rb#L37

我已将用户模型方法更改为undo_changes,我的规格为绿色。