Rspec 通过了 class 方法但失败了实例方法

Rspec passes class method but fails instance method

我正在尝试编写一个失败的 Rspec 测试。实际测试与更长的代码相关联,但我将问题缩小到它正在测试的 class 方法。

这是 Rspec 中的测试:

context "For '.CASH.' as a stock" do
  let!(:cash) { FactoryGirl.create(:stock, symbol: '.CASH.', name: 'cash', status: 'Available') }

  describe "When update_stock runs on it" do
    it "should still have an 'Available' status" do
      # status should be 'Error' and test should fail
      Stock.change_to_error
      expect(cash.status).to eq('Available')
    end
  end
end

这是在 Stock.rb 中测试模型 class 方法:

def self.change_to_error
  self.all.each do |stock|
    stock.status = "Error"
    stock.save
  end
end

出于某种原因,这通过了。但是,如果我将其更改为使用实例方法,它将像它应该的那样失败:

如果stock_spec.rb改为实例方法:

context "For '.CASH.' as a stock" do
let!(:cash) { FactoryGirl.create(:stock, symbol: '.CASH.', name: 'cash', status: 'Available') }

  describe "When update_stock runs on it" do
    it "should still have an 'Available' status" do
        # status should be 'Error' and test should fail
        cash.change_to_error
        expect(cash.status).to eq('Available')
    end
  end
end

而如果stock.rbclass方法变成实例方法:

def change_to_error
  self.status = 'Error'
  self.save
end

这会过去的。不幸的是,我必须使用 class 方法而不是实例方法,因为我想更新数据库中的所有股票。 "Change_to_error" 方法就是用来解决问题的。有谁知道为什么它在应该失败时作为 class 方法传递?但是当它使用实例方法时它正确地失败了?

实际上,发生的事情是 class 方法不会更改 'cash' 的状态属性,但实例方法会。我不知道为什么会这样。

仅供参考,我正在使用 rspec-rails

解决方法:需要在'Stock.change_to_error'之后,expect行之前加上'cash.reload'。

当使用 let! 时,对象是在测试之前创建的。更新对象外部的基础数据会导致实例过时。对其调用 reload 会强制 ActiveRecord 从数据库中刷新它。


当您使用 let 时,RSpec 直到您第一次引用属性时才会调用该块,在本例中为 cash。因此,在您的第一个示例中,您 运行ning change_to_error 根本没有任何记录,然后检查 cash 上的状态,该记录是在 [=16= 行上创建的].在您的第二个示例中,创建了 cash 对象,然后更改为错误。我建议拖尾您的日志以确认这一点 (tail -f log/test.log)

如果更改为let!,RSpec 将在每个示例运行 之前创建对象。另一种方法是在对创建的所有记录调用 change_to_error 之前在您的示例中引用 cash