如何在测试中使用InlineAdapter
? — ActiveJob::TestHelper
不允许你这样做!
我看到你试图使用InlineAdapter
...
我也有同样的愿望——在所有的测试中使用InlineAdapter
。
不幸的是——至少对于RSpec请求测试(ActionDispatch集成测试)——ActiveJob::TestHelper
会自动包含到测试上下文中,并且似乎强制你使用ActiveJob::QueueAdapters::TestAdapter
而不是InlineAdapter
。
gems/activejob-7.0.4.3/lib/active_job/test_helper.rb
就是这样:
ActiveJob::Base.include(TestQueueAdapter)
def before_setup
test_adapter = queue_adapter_for_test
queue_adapter_changed_jobs.each do |klass|
klass.enable_test_adapter(test_adapter)
end
clear_enqueued_jobs
clear_performed_jobs
super
end
def after_teardown
super
queue_adapter_changed_jobs.each { |klass| klass.disable_test_adapter }
end
def queue_adapter_for_test
ActiveJob::QueueAdapters::TestAdapter.new
end
这会导致它完全忽略您可能拥有的任何config.active_job.queue_adapter = :inline
配置(因为它覆盖了queue_adapter
class_attribute
)。
我甚至尝试重写queue_adapter_for_test
:
def queue_adapter_for_test
ActiveJob::QueueAdapters::InlineAdapter.new
end
但它仍然无法工作,因为InlineAdapter
未定义enqueued_jobs
,我们会得到以下错误:
NoMethodError:
undefined method `enqueued_jobs' for #<ActiveJob::QueueAdapters::InlineAdapter:0x00007f7efcce6580>
Did you mean? enqueue
# gems/3.1.0/gems/activejob-7.0.4.3/lib/active_job/test_helper.rb:9:in `enqueued_jobs'
# gems/3.1.0/gems/activejob-7.0.4.3/lib/active_job/test_helper.rb:641:in `clear_enqueued_jobs'
总之... 没有任何
支持的方法可以在包含
ActiveJob::TestHelper
(例如请求测试)的任何地方使用
InlineAdapter
。但总是有解决办法...
解决方法1:覆盖
enqueued_jobs
等,以避免出现错误
假设您正在使用RSpec,您可以添加一个
spec/support/active_job.rb
文件来执行此操作:
module UseInlineQueueAdapter
def queue_adapter_for_test
ActiveJob::QueueAdapters::InlineAdapter.new
end
def enqueued_jobs
if queue_adapter.respond_to?(__callee__)
super
else
[]
end
end
def performed_jobs
if queue_adapter.respond_to?(__callee__)
super
else
[]
end
end
end
RSpec.configure do |config|
config.include UseInlineQueueAdapter
end
你的具体问题 - 仅适用于某些标记测试
在我的情况下,我很高兴只是使用内联适配器来进行所有测试...
但是听起来你想要只在一些被元数据标记的测试中使用它的能力。
这似乎不应该更加困难。看起来你所需要做的就是为queue_adapter_for_test
方法添加一个条件语句:
def queue_adapter_for_test
if example.metadata[:inline_jobs]
ActiveJob::QueueAdapters::InlineAdapter.new
else
ActiveJob::QueueAdapters::TestAdapter.new
end
end
解决方法 #2:按照它的要求使用 TestAdapter
perform_enqueued_jobs
会导致在块执行期间排队的任何作业立即执行(“内联”),因此您原本的代码应该也可以正常工作——但前提是您将 queue_adapter
设置为 TestAdapter
(:test
):
config.around(:each) do |example|
if example.metadata[:perform_enqueued]
perform_enqueued_jobs do
example.run
end
end
end
另一个导致你的方法不起作用的原因是因为
around(:each)
在
before(:each)
之前运行。所以即使
ActiveJob::TestHelper
自动将队列适配器更改为
TestAdapter
,它也是从
before(:each)
(技术上是
before_setup
回调)中进行的。因此,在你的
around(:each)
调用
perform_enqueued_jobs
时,
ActiveJob::Base.queue_adapter
应该仍然保持配置中的状态。
假设你在
config/environments/test.rb
中有像
config.active_job.queue_adapter = :inline
这样的设置?正如其他答案所指出的那样,如果你想让你的方法起作用,你必须将其改为
:test
。
因为正如错误提示的那样,
InlineAdapter
没有
enqueued_jobs
的概念,相应地,也没有定义名为
perform_enqueued_jobs
的方法。
以下是我想出来的解决方案,似乎可以工作:
RSpec.configure do |config|
config.include(Module.new do
def queue_adapter_for_test
if ActiveJob::Base.queue_adapter.is_a?(ActiveJob::QueueAdapters::TestAdapter)
ActiveJob::Base.queue_adapter
else
super
end
end
end)
config.around do |example|
if example.metadata[:perform_enqueued_jobs]
perform_enqueued_jobs do
example.run
end
else
example.run
end
end
end
现在,您可以继续注释任何示例组或示例,其中您想要立即执行入队作业!
it "performs the job immediately as soon as enqueued", :perform_enqueued_jobs do
end
尝试了这两种解决方法后,我现在建议使用第二种,因为它更灵活,仍然可以让您在需要异步排队的任何测试中进行此操作,但是在您可以使用更简单的内联执行选项时,可以切换到该选项...