所以我有这个型号代码:
def self.cleanup
Transaction.where("created_at < ?", 30.days.ago).destroy_all
end
和这个rspec单元测试:
describe 'self.cleanup' do
before(:each) do
@transaction = Transaction.create(seller:item.user, buyer:user, item:item, created_at:6.weeks.ago)
end
it 'destroys all transactions more than 30 days' do
Transaction.cleanup
expect(@transaction).not_to exist_in_database
end
end
与这些工厂合作:
FactoryGirl.define do
factory :transaction do
association :seller, factory: :user, username: 'IAMSeller'
association :buyer, factory: :user, username: 'IAmBuyer'
association :item
end
factory :old_transaction, parent: :transaction do
created_at 6.weeks.ago
end
end
使用此rspec自定义匹配器:
RSpec::Matchers.define :exist_in_database do
match do |actual|
actual.class.exists?(actual.id)
end
end
当我将规格更改为:
describe 'self.cleanup' do
let(:old_transaction){FactoryGirl.create(:old_transaction)}
it 'destroys all transactions more than 30 days' do
Transaction.cleanup
expect(old_transaction).not_to exist_in_database
end
end
测试失败。我还尝试手动创建一个事务并将其分配给:old_transaction with let()但这也使测试失败。
为什么它只在我在before(:each)块中使用实例变量时才会通过?
提前致谢!
编辑:失败的输出
1) Transaction self.cleanup destroys all transactions more than 30 days
Failure/Error: expect(old_transaction).not_to exist_in_database
expected #<Transaction id: 2, seller_id: 3, buyer_id: 4, item_id: 2, transaction_date: nil, created_at: "2014-02-26 10:06:30", updated_at: "2014-04-09 10:06:32", buyer_confirmed: false, seller_confirmed: false, cancelled: false> not to exist in database
# ./spec/models/transaction_spec.rb:40:in `block (3 levels) in <top (required)>'
答案 0 :(得分:5)
let
已加载延迟。因此,在您失败的规范中,这是事件的顺序:
Transaction.cleanup
old_transaction = FactoryGirl.create(:old_transaction)
expect(old_transaction).not_to exist_in_database
因此,在您尝试清理之后,会创建交易。
您有多种选择:
let
用于此除非你有其他规格想要告诉其他开发者:
我完全打算让所有这些规范引用完全相同的对象
我个人觉得,你最好在内联交易。
it do
transaction = FactoryGirl.create(:old_transaction)
Transaction.cleanup
expect(transaction).not_to exist_in_database
end
change
匹配器这是我个人的选择,因为它清楚地表明了预期的行为:
it do
expect{
Transaction.cleanup
}.to change{ Transaction.exists?(old_transaction.id) }.to false
end
这适用于let
,因为change
块在expect
块之前和之后运行。因此,在第一次传递时,old_transaction
被实例化,因此可以检查id
。
before
或参考old_transaction
IMO这看起来很奇怪:
before do
old_transaction
end
it do
old_transaction # if you don't use the before
Transaction.clean
# ...
end
let!
let!
未加载延迟。从本质上讲,它是执行普通let
的别名,然后在before
中调用它。我不喜欢这种方法(详见The bang is for surprise)。
答案 1 :(得分:1)
我认为你只是偶然在一个&#34;中打字错误:&#34;
试试这个规范:
describe 'self.cleanup' do
let(:old_transaction){FactoryGirl.create(:old_transaction)}
it 'destroys all transactions more than 30 days' do
Transaction.cleanup
expect(old_transaction).not_to exist_in_database
end
end