rspec中的事务性工具阻止调用after_commit,但即使我用
禁用它们也是如此RSpec.configure do |config|
config.use_transactional_fixtures = false
end
after_commit callback
未运行。
这是一个带有最新版本的rspec / rails的rails应用程序: git://github.com/sheabarton/after_commit_demo.git
答案 0 :(得分:25)
解决此问题的一种方法是手动触发commit
回调。例如:
describe SomeModel do
subject { ... }
context 'after_commit' do
after { subject.run_callbacks(:commit) }
it 'does something' do
subject.should_receive(:some_message)
end
end
end
有点晚了,但希望这有助于其他人。
答案 1 :(得分:9)
在我的情况下,我使用下面的database_cleaner设置解决了这个问题:
config.use_transactional_fixtures = false
config.before(:suite) do
DatabaseCleaner.strategy = :deletion
DatabaseCleaner.clean_with(:truncation)
end
config.before(:each) do
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
答案 2 :(得分:8)
这与@ jamesdevar上面的答案类似,但是我无法添加代码块,所以我必须单独输入。
您无法更改整个规范套件的策略。您可以继续全局使用:transaction
,然后根据需要使用:deletion
或:truncation
(它们都有效)。只需在相关规范中添加一个标记即可。
config.use_transactional_fixtures = false
config.before(:suite) do
# The :transaction strategy prevents :after_commit hooks from running
DatabaseCleaner.strategy = :transaction
DatabaseCleaner.clean_with(:truncation)
end
config.before(:each, :with_after_commit => true) do
DatabaseCleaner.strategy = :truncation
end
然后,在您的规格中:
describe "some test requiring after_commit hooks", :with_after_commit => true do
答案 3 :(得分:5)
如果您使用database_cleaner,您仍会遇到此问题。我正在使用test_after_commit宝石,这似乎对我有用。
答案 4 :(得分:2)
This Gist帮助了我。
即使使用事务性工具,它也会修补ActiveRecord来触发after_commit回调。
module ActiveRecord
module ConnectionAdapters
module DatabaseStatements
#
# Run the normal transaction method; when it's done, check to see if there
# is exactly one open transaction. If so, that's the transactional
# fixtures transaction; from the model's standpoint, the completed
# transaction is the real deal. Send commit callbacks to models.
#
# If the transaction block raises a Rollback, we need to know, so we don't
# call the commit hooks. Other exceptions don't need to be explicitly
# accounted for since they will raise uncaught through this method and
# prevent the code after the hook from running.
#
def transaction_with_transactional_fixtures(options = {}, &block)
rolled_back = false
transaction_without_transactional_fixtures do
begin
yield
rescue ActiveRecord::Rollback => e
rolled_back = true
raise e
end
end
if !rolled_back && open_transactions == 1
commit_transaction_records(false)
end
end
alias_method_chain :transaction, :transactional_fixtures
#
# The @_current_transaction_records is an stack of arrays, each one
# containing the records associated with the corresponding transaction
# in the transaction stack. This is used by the
# `rollback_transaction_records` method (to only send a rollback hook to
# models attached to the transaction being rolled back) but is usually
# ignored by the `commit_transaction_records` method. Here we
# monkey-patch it to temporarily replace the array with only the records
# for the top-of-stack transaction, so the real
# `commit_transaction_records` method only sends callbacks to those.
#
def commit_transaction_records_with_transactional_fixtures(commit = true)
unless commit
real_current_transaction_records = @_current_transaction_records
@_current_transaction_records = @_current_transaction_records.pop
end
begin
commit_transaction_records_without_transactional_fixtures
rescue # works better with that :)
ensure
unless commit
@_current_transaction_records = real_current_transaction_records
end
end
end
alias_method_chain :commit_transaction_records, :transactional_fixtures
end
end
end
将这个新文件放在Rails.root / spec / support目录中,例如spec/support/after_commit_with_transactional_fixtures.rb
。
Rails 3会自动将其加载到测试环境中。