Ruby on rails 使用RSpec和mocking在提交后进行测试

Ruby on rails 使用RSpec和mocking在提交后进行测试,ruby-on-rails,ruby,rspec,mocking,Ruby On Rails,Ruby,Rspec,Mocking,我有一个模型潜在客户和一个回调:在提交之后:创建,:发送给\u SPL 我使用的是Rails-4.1.0、ruby-2.1.1、RSpec 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_recor

我有一个模型潜在客户和一个回调:
在提交之后:创建,:发送给\u SPL

我使用的是Rails-4.1.0、ruby-2.1.1、RSpec

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) 该规范也未通过:

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) 这一个正在通过,但我认为它不是在您提交回调后进行测试:

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
在Rails中提交回调后测试的最佳方法是什么?

尝试使用gem

或者在spec/support/helpers/test\u after\u commit.rb-

中添加以下代码,我认为这应该是一个答案:

您还可以使用
subject.run\u回调(:commit)

还要注意的是,这个问题(提交回调在事务测试中没有被调用)应该在rails 5.0+中得到修复,因此您可能希望在升级期间删除任何可能使用的解决方法。请参阅:

我正在使用的配置可以轻松地在事务和截断之间切换,由于速度原因,前者是首选,但后者可以用于测试回调

RSpec
before
after
处理程序处理作用域,因此如果要将截断设置为作用域,请在
处理程序之前定义一个

config.before(:each, truncate: true) do
  DatabaseCleaner.strategy = :truncation
end
现在,要将此配置用于
descripe
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
完整的挂钩配置:(存储在
spec/support/database\u cleaner.rb


更新Rails5

回调处理确实已经修复,但您可能仍然需要大量使用
#reload

例如:
给定一个定义如下所示的创建后回调的模型:

after_create_commit { assign_some_association }
您可以通过以下方式指定此行为:

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

我用这样的东西

describe 'some method on record' do
  let(:record) { create(:some_record) }
  let(:update_block) { ->(record) { record.save! } } # define an labmda that will be called in a transaction block
  let(:result_method) { :some_method } # define a method to be called
  let(:result) do
    record.class_eval <<~EVAL, __FILE__, __LINE__ + 1
      after_commit :_record_result
       def _record_result
        @_result = public_send(:#{result_method})
      end
    EVAL

    record.transaction do
      update_block.call(record)
    end

    record.instance_variable_get(:'@_result')
  end

  before do
    # apply changes to record
  end

  it 'returns the correct result' do
    expect(result).to eq(some_value)
  end
end
描述“记录中的某些方法”吗
let(:record){create(:some_record)}
让(:update_block){->(record){record.save!}}}}定义一个将在事务块中调用的labmda
让(:result_method){:some_method}#定义一个要调用的方法
让(:结果)去做

record.class\u eval您还可以使用
subject.run\u回调(:commit)
在块体的末尾
it
这个gem对Rails 3和Rails 4非常有效。在Rails 5中,它不再是必需的,因为它已添加到核心:如果使用
on::update
定义回调,则我不处理
4.2.7
。在运行回调之前,我还必须执行
subject.instance\u variable\u get(:@\u start\u transaction\u state)[:new\u record]=false
,以使其工作,尽管它执行回调,但self.previous\u更改为{},这不是真的。怎么弄到的?
describe 'some method on record' do
  let(:record) { create(:some_record) }
  let(:update_block) { ->(record) { record.save! } } # define an labmda that will be called in a transaction block
  let(:result_method) { :some_method } # define a method to be called
  let(:result) do
    record.class_eval <<~EVAL, __FILE__, __LINE__ + 1
      after_commit :_record_result
       def _record_result
        @_result = public_send(:#{result_method})
      end
    EVAL

    record.transaction do
      update_block.call(record)
    end

    record.instance_variable_get(:'@_result')
  end

  before do
    # apply changes to record
  end

  it 'returns the correct result' do
    expect(result).to eq(some_value)
  end
end