假设我正在使用pg
gem和RSpec,我应该采取什么方法来正确测试我的LISTEN
和NOTIFY
语句是否有效? pg的wait_for_notify块,所以看起来我不能“通知,然后听”,或“听,然后通知”。我忽略了什么吗?
例如:
it "notifies" do
conn = ActiveRecord::Base.connection
it_ran = false
conn.execute "LISTEN my_channel"
conn.execute "NOTIFY my_channel, 'hello'"
conn.wait_for_notify(1) do |channel, pid, payload|
it_ran = true
end
expect(it_ran).to eq true
end
修改
这适用于控制器,甚至是rails控制台,但由于某种原因,它在RSpec测试中不起作用。奇怪的是,直接使用pg
gem确实有效。为什么ActiveRecord可能无法在这种情况下工作?
答案 0 :(得分:1)
wait_for_notify()
仅在需要时阻止。也就是说,当通知队列中还没有东西时。
在您的代码中,队列中已经存在基于您的第一个NOTIFY
的通知,因此wait_for_notify()将立即返回并且将设置it_ran。
如果我撕掉ActiveRecord的东西并直接使用pg,这正是发生的事情。
答案 1 :(得分:0)
原来问题在于DatabaseCleaner。有了这个,我尝试使用其他策略而不是交易,但没有任何效果;似乎让LISTEN / NOTIFY
处理ActiveRecord连接的唯一方法是禁用它进行一次测试。
以下是我最终为特定测试禁用DatabaseCleaner的方法。在我的支持配置文件中:
RSpec.configure do |config|
# BEFORE:
# config.before(:each) do
# DatabaseCleaner.strategy = :transaction
# end
# AFTER:
config.before(:each) do |test|
unless test.metadata[:no_database_cleaner]
DatabaseCleaner.strategy = :transaction
end
end
end
在我的spec文件中:
RSpec.describe "Postgres LISTEN / NOTIFY" do
it "notifies", :no_database_cleaner => true do
# [clipped]
end
end
现在,只要我需要测试LISTEN / NOTIFY
,我就会将:no_database_cleaner => true
添加到it
块。