Rails中的这个回调事情一直困扰着我。问题是,我不喜欢他们。主要是因为他们减慢了我的测试速度,因为我必须在我的单元测试中点击数据库以便持久化对象,这会触发回调(例如,after_save)。
我将使用一个简单的例子说明我想做些什么来让自己更清楚。假设我有一个账户,每次我提款,我都要从余额中扣除金额。我的模特是:
class Withdraw < ActiveRecord::Base
belongs_to :account
after_save :update_account_balance
private
def update_account_balance
self.account.balance -= self.amount
self.account.save
end
end
class Account < ActiveRecord::Base
has_many :withdraws
end
所以,如果我要测试那种行为,我将要做的是(使用RSpec):
describe Withdraw
it 'updates the account balance' do
account = Account.create({ :name => "foo", :balance => 100 })
withdraw.create({ :amount => 10, :account => account })
account.balance.should == 90
end
end
请注意,我必须在该单元测试中两次点击数据库。这在一个简单的项目中可以,但是当测试套件增长时(500个左右),它开始成为一种负担。
我可以将update_account_balance
方法公开并从控制器中调用它,但我认为它的业务逻辑并不属于控制器代码。
我已经尝试使用谷歌搜索解决方案,但无法找到解决方案。你们如何使用快速测试套件解决这个问题?
提前致谢。
答案 0 :(得分:2)
我认为你的问题是你做了一个withdrawal
隐式的动作(即它是通过创建Withdraw
对象而发生的)
我认为有更好的方法。
account.withdraw!(1000)
代码可能如下所示。
class Account
def withdraw!(amount)
transaction do
withdrawal = self.withdrawals.build(:amount => amount)
self.subtract_balance(amount)
withdrawal.save!
end
end
private
def subtract_balance(amount)
connection.execute(
"UPDATE #{self.class.table_name} SET balance = balance - #{amount} WHERE id = #{self.id}"
)
end
end