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
。
我正在尝试编写一个失败的 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
。