I have a model Lead and a callback: after_commit :create, :send_to_SPL
我有一个模型线索和一个回调:after_commit:create,:send_to_SPL
I am using Rails-4.1.0, ruby-2.1.1, RSpec.
我正在使用Rails-4.1.0、ruby-2.1.1、RSpec。
1) This spec is not passing:
1)此规格未通过:
context 'callbacks' do
it 'shall call \'send_to_SPL\' after create' do
expect(lead).to receive(:send_to_SPL)
lead = Lead.create(init_hash)
p lead.new_record? # => false
end
end
2) This spec is not passing too:
2)此规格也不合格:
context 'callbacks' do
it 'shall call \'send_to_SPL\' after create' do
expect(ActiveSupport::Callbacks::Callback).to receive(:build)
lead = Lead.create(init_hash)
end
end
3) This one is passing, but I think it is not testing after_commit callback:
3)这个正在传递,但我认为它不是在测试after_commit回调:
context 'callbacks' do
it 'shall call \'send_to_SPL\' after create' do
expect(lead).to receive(:send_to_SPL)
lead.send(:send_to_SPL)
end
end
What is the best way to test after_commit callbacks in Rails?
在Rails中测试after_commit回调的最佳方式是什么?
4 个解决方案
#1
34
Try to use test_after_commit gem
尝试使用test_after_commit gem
or add following code in spec/support/helpers/test_after_commit.rb - Gist
或者在spec/support/helper /test_after_commit中添加以下代码。rb -要点
#2
39
I thought Mihail Davydenkov's comment deserved to be an answer:
我认为米海尔·达维登科夫的评论应该是一个答案:
You can also use
subject.run_callbacks(:commit)
.您还可以使用subject.run_callbacks(:commit)。
Also note that this issue (commit callbacks not getting called in transactional tests) should be fixed in rails 5.0+ so you may wish to make a note to remove any workarounds you may use in the meantime when you upgrade. See: https://github.com/rails/rails/pull/18458
还要注意,这个问题(提交回调不会在事务测试中被调用)应该在rails 5.0+中得到解决,因此您可能希望在升级时删除您可能在此期间使用的任何工作区。参见:https://github.com/rails/rails/pull/18458
#3
4
I'm using DatabaseCleaner, with a configuration where I can easily switch between transaction and truncation, where the former is preferred, because of speed, but where the latter can be used for testing callbacks.
我使用DatabaseCleaner,配置了一个配置,在这个配置中,可以方便地在事务和截断之间切换,因为前者是首选的,因为速度,但是后者可以用于测试回调。
RSpec before
and after
handlers work with scopes, so if you want to make truncation a scope, define a before
handler;
RSpec在处理程序之前和之后处理作用域,所以如果您想使截断成为作用域,请定义一个before处理程序;
config.before(:each, truncate: true) do
DatabaseCleaner.strategy = :truncation
end
And now to use this configuration for a describe
, context
or it
block, you should declare it like:
现在使用这个配置来描述,context或it块,你应该声明它:
describe "callbacks", truncate: true do
# all specs within this block will be using the truncation strategy
describe "#save" do
it "should trigger my callback" do
expect(lead).to receive(:send_to_SPL)
lead = Lead.create(init_hash)
end
end
end
Complete hook configuration: (store in spec/support/database_cleaner.rb
)
完整的hook配置:(存储在spec/support/database_clean .rb中)
RSpec.configure do |config|
config.before(:suite) do
DatabaseCleaner.clean_with(:truncation)
end
config.before(:each) do
DatabaseCleaner.strategy = :transaction
end
config.before(:each, truncate: true) do
DatabaseCleaner.strategy = :truncation
end
config.before(:each) do
DatabaseCleaner.start
end
config.append_after(:each) do
DatabaseCleaner.clean
end
end
#4
1
Update for Rails5.
Rails5更新。
Callback handling has indeed been fixed, but you may still need to use #reload
liberally.
回调处理确实已经修复,但是您可能仍然需要大量地使用#reload。
An example:
Given a model that defines an after-create callback like so:
例如:给定一个模型,该模型定义一个后创建回调,如下所示:
after_create_commit { assign_some_association }
You can spec this behavior with:
你可以用以下方法来规范这种行为:
describe "callbacks" do
describe "assigning_some_association" do
subject(:saving) { record.save!; record.reload } # reload here is important
let(:record) { build(:record) }
it "assigns some association after commit" do
expect{ saving }.to(
change{ record.some_association_id }.from(nil).to(anything)
)
end
end
end
#1
34
Try to use test_after_commit gem
尝试使用test_after_commit gem
or add following code in spec/support/helpers/test_after_commit.rb - Gist
或者在spec/support/helper /test_after_commit中添加以下代码。rb -要点
#2
39
I thought Mihail Davydenkov's comment deserved to be an answer:
我认为米海尔·达维登科夫的评论应该是一个答案:
You can also use
subject.run_callbacks(:commit)
.您还可以使用subject.run_callbacks(:commit)。
Also note that this issue (commit callbacks not getting called in transactional tests) should be fixed in rails 5.0+ so you may wish to make a note to remove any workarounds you may use in the meantime when you upgrade. See: https://github.com/rails/rails/pull/18458
还要注意,这个问题(提交回调不会在事务测试中被调用)应该在rails 5.0+中得到解决,因此您可能希望在升级时删除您可能在此期间使用的任何工作区。参见:https://github.com/rails/rails/pull/18458
#3
4
I'm using DatabaseCleaner, with a configuration where I can easily switch between transaction and truncation, where the former is preferred, because of speed, but where the latter can be used for testing callbacks.
我使用DatabaseCleaner,配置了一个配置,在这个配置中,可以方便地在事务和截断之间切换,因为前者是首选的,因为速度,但是后者可以用于测试回调。
RSpec before
and after
handlers work with scopes, so if you want to make truncation a scope, define a before
handler;
RSpec在处理程序之前和之后处理作用域,所以如果您想使截断成为作用域,请定义一个before处理程序;
config.before(:each, truncate: true) do
DatabaseCleaner.strategy = :truncation
end
And now to use this configuration for a describe
, context
or it
block, you should declare it like:
现在使用这个配置来描述,context或it块,你应该声明它:
describe "callbacks", truncate: true do
# all specs within this block will be using the truncation strategy
describe "#save" do
it "should trigger my callback" do
expect(lead).to receive(:send_to_SPL)
lead = Lead.create(init_hash)
end
end
end
Complete hook configuration: (store in spec/support/database_cleaner.rb
)
完整的hook配置:(存储在spec/support/database_clean .rb中)
RSpec.configure do |config|
config.before(:suite) do
DatabaseCleaner.clean_with(:truncation)
end
config.before(:each) do
DatabaseCleaner.strategy = :transaction
end
config.before(:each, truncate: true) do
DatabaseCleaner.strategy = :truncation
end
config.before(:each) do
DatabaseCleaner.start
end
config.append_after(:each) do
DatabaseCleaner.clean
end
end
#4
1
Update for Rails5.
Rails5更新。
Callback handling has indeed been fixed, but you may still need to use #reload
liberally.
回调处理确实已经修复,但是您可能仍然需要大量地使用#reload。
An example:
Given a model that defines an after-create callback like so:
例如:给定一个模型,该模型定义一个后创建回调,如下所示:
after_create_commit { assign_some_association }
You can spec this behavior with:
你可以用以下方法来规范这种行为:
describe "callbacks" do
describe "assigning_some_association" do
subject(:saving) { record.save!; record.reload } # reload here is important
let(:record) { build(:record) }
it "assigns some association after commit" do
expect{ saving }.to(
change{ record.some_association_id }.from(nil).to(anything)
)
end
end
end