如何摆脱必须在RSpec重装?

时间:2012-10-21 05:22:15

标签: ruby-on-rails ruby-on-rails-3 rspec rspec-rails

我在运行规范时遇到了一个奇怪的行为。

此代码不起作用(baz.viewed未更新),除非我取消注释第baz.reload行。

describe "#..." do
  it "..." do
    baz = user.notifications.create!(title: "baz")
    baz.update_attribute(:created_at, Time.now + 3.day)

    # it sets `viewed` to `true` in the model to which `baz` is referred.
    user.dismiss_latest_notification!

    # baz.reload
    baz.viewed.should == true
  end
end

我没有使用SporkGuard运行规范,但无论如何都不会重新加载此模型。

为什么会发生这种情况?或者,通常的做法是在规范中调用.reload方法?

1 个答案:

答案 0 :(得分:4)

让我让这个案例更加清晰: 当行baz = user.notifications.create!(title: "baz")被执行时,会发生两件事:

1-新的通知行将添加到数据库中。

2-在内存中创建一个对象,表示该行,并且可以使用变量baz引用。 请注意,baz的查看值为false(同时行也是如此)。

现在我没有看到方法的实际实现

user.dismiss_latest_notification!

但是既然你没有传递任何变量,我肯定知道你有一个本着精神的代码:

def dismiss_latest_notification!
  latest_notification = self.notifications.last
  latest_notification.viewed = true
  latest_notification.save!
end

这里重要的一行是

   latest_notification = self.notifications.last

在内存中创建一个对象,表示同一行baz,但存储在另一个变量中 - latest_notification。

现在,您有两个表示DB中同一行的变量。当您在latest_notification上执行保存时,将使用正确的查看值更新数据库,但不会以任何方式更新变量baz以反映此更改。您别无选择,只能通过对其执行reload来强制使用最新值从数据库进行更新。

我认为摆脱重装的正确方法是稍微改变测试:

而不是

baz.viewed.should == true

使用:

user.notifications.last.viewed.should be_true

在我看来,它更适合这个特定测试的目的。