ruby-on-rails - Rails 3 : ActiveRecord observer: after_commit callback doesn't fire during tests, 但 after_save 确实触发

标签 ruby-on-rails ruby-on-rails-3 rspec observers

我有一个 Rails 3 应用程序。我对某些模型使用 after_save 回调,对其中一个模型使用 after_commit 回调。所有代码都运行良好,但在 RSpec 测试期间,当我保存 Thing 模型时,after_commit 回调不会被调用。

例如

class ThingObserver  <  ActiveRecord:Observer
  observe Thing
  def after_commit(thing)
    puts thing.inspect
  end
end

如果我将方法名称更改为 after_save,它会在测试期间正常调用。我需要能够为这个特定模型使用 after_commit 因为在某些情况下,对“事物”的更改发生在 Web 服务器中,但观察者的影响发生在 Sidekiq worker 中,并且 after_save 不保证数据在 worker 准备好时已提交和可用。

RSpec 的配置在 spec/spec_helper.rb 中如下所示

Rspec.configure do |config|
  #yada yada
  config.use_transactional_fixtures = true
  #yada yada
end

我还调整了 rake db:create 以便它从 structure.sql 文件中提取。在 lib/tasks/db.rb 中

task setup: [ 'test:ensure_environment_is_test', 'db:create', 'db:structure:load', 'db:migrate', 'db:seed' ]

我这样做是为了运行测试以确保数据库强制执行外键约束。

有没有办法在不使 Rspec use_transactional_fixtures == false 的情况下同时运行 after_save 和 after_commit 回调?

或者,是否有办法仅针对该测试或该测试文件将 config.use_transactional_fixtures 设置为“false”?

最佳答案

要正确执行数据库提交,您需要启用 config.use_transactional_fixtures,但我建议您考虑不同的策略,因为为了良好的测试设计,默认情况下禁用该选项,以强制执行您的测试尽可能统一和隔离。

首先,您可以使用 #run_callbacks(type) 运行 ActiveRecord 回调,在您的情况下为 model.run_callbacks(:commit)

我的首选策略是拥有一个包含您要运行的逻辑的方法,然后使用方法名称声明 Hook ,然后通过直接调用它来测试方法行为,并测试 Hook 运行时是否调用了该方法。

class Person
  after_commit :register_birth

  def register_birth
    # your code
  end
end

describe Person do
  describe "registering birth" do
    it "registers ..." do
    end

    it "runs after database insertion" do
      expect(model).to receive(:register_birth)
      model.run_callbacks(:commit)
    end
  end
end

这假设您在回调上拥有的任何逻辑对于模型状态都不是必需的,即不会将其更改为您需要立即使用的东西,并且与它交互的任何其他模型都对它无动于衷。因此不需要在测试上下文中运行。这是一个强大的设计原则,从长远来看,通过要求一些与您正在测试的单元无关的属性被设置为仅在您不关心的回调中使用,从而防止回调失控并为测试生成依赖关系大约在那一刻。

但是,最终你比陌生人更了解你的领域和设计要求,所以,如果你真的需要 after_commit 运行,你可以使用 model.run_callbacks(:提交)。只需将其封装在您的工厂/固定装置上,您就不必每次都记住它。

关于ruby-on-rails - Rails 3 : ActiveRecord observer: after_commit callback doesn't fire during tests, 但 after_save 确实触发,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27139012/

相关文章:

ruby-on-rails - 限制用户在相关模型的 Controller 中的访问

ruby-on-rails - 错误在 rails 中显示两次

ruby-on-rails - Heroku 部署 Gemfile.lock 问题

ruby-on-rails - 验证 html 文本中是否存在 url

ruby-on-rails - FactoryGirl owns_to 关联和 validates_presence_of 失败 - 外键已关联,但对象未关联

ruby-on-rails-3 - 如何使用rspec生成 Controller 规范?

ruby-on-rails - 如何使用 RSpec 测试 WebSockets(使用 Pusher)?

ruby-on-rails - 更改 Rails 中测试的主机名

ruby-on-rails - rails : Turbo Frame/Turbo Stream element is not rendered the SECOND time I trigger it

ruby-on-rails - Rails 中的唯一搜索结果