我正在尝试编写失败的Rspec测试。实际测试与更长的代码相关联,但我将问题缩小到它正在测试的类方法。
以下是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中测试模型类方法:
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.rb类方法变成了实例方法:
def change_to_error
self.status = 'Error'
self.save
end
这会过去。不幸的是,我必须使用类方法而不是实例方法,因为我想更新数据库中的所有股票。 “Change_to_error”方法就是解决问题的方法。有没有人知道它为什么会失败时作为类方法传递?但是当它使用实例方法时它会正确失败吗?
实际上,正在发生的是类方法不会更改'cash'的status属性,但实例方法会更改。我不知道为什么会这样。
仅供参考,我正在使用rspec-rails
答案 0 :(得分:1)
解决方案:需要在'Stock.change_to_error'之后和期望行之前加上'cash.reload'。
使用mvn archetype:create
时,在测试之前创建对象。更新对象外部的基础数据会导致实例过时。在其上调用let!
会强制ActiveRecord从数据库中刷新它。
当您使用reload
时,RSpec不会在您第一次引用属性时调用该块,在本例中为let
。因此,在您的第一个示例中,您根本没有记录cash
,然后检查change_to_error
上的状态,这是在cash
行上创建的记录。在第二个示例中,创建了expect
对象,然后更改为错误。我建议拖尾你的日志来确认这个(cash
)
如果更改为tail -f log/test.log
,RSpec将在每个示例运行之前创建对象。另一种方法是在您的示例中引用let!
,然后在创建的所有记录上调用cash
。