使用RSpec和mock测试after_commit。

时间:2021-12-26 01:21:19

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