ruby-on-rails - rake 任务被多次调用
问题描述
我在测试我的 Rails 任务时遇到了一个奇怪的问题。当我为我的 rake 任务运行所有测试时,它们会被多次调用,但是当我只运行一个测试文件时,一切都会突然工作。这是一个示例代码:
耙任务
namespace :after_party do
desc 'Deployment task: create_users_on_another_app'
task create_users_on_another_app: :environment do
...some code
AppClient.post(some_url, some_payload, some_header)
...some more code
AfterParty::TaskRecord.create version: '20190620160110'
end
end
end
rspec 测试
describe 'create_users_on_another_app' do
before do
allow(AppClient).to receive(:post).and_return(some_response)
end
it "creates users" do
expect(AppClient).to receive(:post).with(some_url, some_data, some_header)
puts "JUST BEFORE INVOKING THE TASK: "
Rake::Task['after_party:create_users_on_another_app'].invoke
puts "DONE"
end
end
在控制台输出中,我可以看到如下内容:
> JUST BEFORE INVOKING THE TASK:
> Running deploy task 'create_users_on_another_app'
> Running deploy task 'create_users_on_another_app'
> DONE
所以任务被调用了两次。
我不知道为什么会发生这种情况,而且我 100% 确定我没有在我的代码中调用它两次。我怀疑要么是我缺少的 rspec 的一些 rake 配置,要么是我正在使用的 rake 任务的 gem - after_party
。
我很难调试它,在我处于导致问题的 rake 任务时尝试使用show-stack
with binding.pry
,但没有设法看到在什么时候触发了额外的 rake 任务。
有人见过这样的问题吗?
编辑:在rake 任务it
之前,在块内运行 show-stack 命令的堆栈跟踪:invoke
=> #0 <main>
#1 [block] block in run <Byebug::PryProcessor#run(&_block)>
#2 [method] run <Byebug::PryProcessor#run(&_block)>
#3 [method] resume_pry <Byebug::PryProcessor#resume_pry()>
#4 [method] at_line <Byebug::PryProcessor#at_line()>
#5 [method] at_line <Byebug::Context#at_line()>
#6 [block] block (2 levels) in <top (required)>
#7 [block] block in run <RSpec::Core::Example#run(example_group_instance, reporter)>
#8 [block] block in with_around_and_singleton_context_hooks <RSpec::Core::Example#with_around_and_singleton_context_hooks()>
#9 [block] block in with_around_example_hooks <RSpec::Core::Example#with_around_example_hooks()>
#10 [block] block in run <RSpec::Core::Hooks::HookCollections#run(position, scope, example_or_group)>
#11 [block] block in run_around_example_hooks_for <RSpec::Core::Hooks::HookCollections#run_around_example_hooks_for(example)>
#12 [method] call <RSpec::Core::Example::Procsy#call(*args, &block)>
#13 [block] block (2 levels) in <module:MinitestLifecycleAdapter>
#14 [method] instance_exec <RSpec::Core::Example#instance_exec(*args, &block)>
#15 [method] execute_with <RSpec::Core::Hooks::AroundHook#execute_with(example, procsy)>
#16 [block] block (2 levels) in run_around_example_hooks_for <RSpec::Core::Hooks::HookCollections#run_around_example_hooks_for(example)>
#17 [method] call <RSpec::Core::Example::Procsy#call(*args, &block)>
#18 [block] block (3 levels) in <top (required)>
#19 [method] perform_enqueued_jobs <ActiveJob::TestHelper#perform_enqueued_jobs(?, ?)>
#20 [block] block (2 levels) in <top (required)>
#21 [method] instance_exec <RSpec::Core::Example#instance_exec(*args, &block)>
#22 [method] execute_with <RSpec::Core::Hooks::AroundHook#execute_with(example, procsy)>
#23 [block] block (2 levels) in run_around_example_hooks_for <RSpec::Core::Hooks::HookCollections#run_around_example_hooks_for(example)>
#24 [method] call <RSpec::Core::Example::Procsy#call(*args, &block)>
#25 [block] block in run <RSpec::Retry#run()>
#26 [method] run <RSpec::Retry#run()>
#27 [method] run_with_retry <RSpec::Core::Example::Procsy#run_with_retry(opts=?)>
#28 [block] block (2 levels) in setup <self.setup(UNKNOWN) (undefined method)>
#29 [method] instance_exec <RSpec::Core::Example#instance_exec(*args, &block)>
#30 [method] execute_with <RSpec::Core::Hooks::AroundHook#execute_with(example, procsy)>
#31 [block] block (2 levels) in run_around_example_hooks_for <RSpec::Core::Hooks::HookCollections#run_around_example_hooks_for(example)>
#32 [method] call <RSpec::Core::Example::Procsy#call(*args, &block)>
#33 [method] run_around_example_hooks_for <RSpec::Core::Hooks::HookCollections#run_around_example_hooks_for(example)>
#34 [method] run <RSpec::Core::Hooks::HookCollections#run(position, scope, example_or_group)>
#35 [method] with_around_example_hooks <RSpec::Core::Example#with_around_example_hooks()>
#36 [method] with_around_and_singleton_context_hooks <RSpec::Core::Example#with_around_and_singleton_context_hooks()>
#37 [method] run <RSpec::Core::Example#run(example_group_instance, reporter)>
#38 [block] block in run_examples <RSpec::Core::ExampleGroup.run_examples(reporter)>
#39 [method] run_examples <RSpec::Core::ExampleGroup.run_examples(reporter)>
#40 [method] run <RSpec::Core::ExampleGroup.run(reporter=?)>
#41 [block] block (3 levels) in run_specs <RSpec::Core::Runner#run_specs(example_groups)>
#42 [block] block (2 levels) in run_specs <RSpec::Core::Runner#run_specs(example_groups)>
#43 [method] with_suite_hooks <RSpec::Core::Configuration#with_suite_hooks()>
#44 [block] block in run_specs <RSpec::Core::Runner#run_specs(example_groups)>
#45 [method] report <RSpec::Core::Reporter#report(expected_example_count)>
#46 [method] run_specs <RSpec::Core::Runner#run_specs(example_groups)>
#47 [method] run <RSpec::Core::Runner#run(err, out)>
#48 [method] run <RSpec::Core::Runner.run(args, err=?, out=?)>
#49 [method] invoke <RSpec::Core::Runner.invoke()>
#50 [top] <top (required)>
#51 [eval] <main>
#52 [main] <main>
还从 rake 任务本身内部附加堆栈跟踪:
=> #0 <main>
#1 [block] block in run <Byebug::PryProcessor#run(&_block)>
#2 [method] run <Byebug::PryProcessor#run(&_block)>
#3 [method] resume_pry <Byebug::PryProcessor#resume_pry()>
#4 [method] at_line <Byebug::PryProcessor#at_line()>
#5 [method] at_line <Byebug::Context#at_line()>
#6 [block] block (2 levels) in <top (required)>
#7 [block] block in execute <Rake::Task#execute_without_bugsnag(args=?)>
#8 [method] execute <Rake::Task#execute_without_bugsnag(args=?)>
#9 [method] execute_with_bugsnag <Rake::Task#execute_with_bugsnag(args=?)>
#10 [block] block in invoke_with_call_chain <Rake::Task#invoke_with_call_chain(task_args, invocation_chain)>
#11 [method] mon_synchronize <MonitorMixin#mon_synchronize()>
#12 [method] invoke_with_call_chain <Rake::Task#invoke_with_call_chain(task_args, invocation_chain)>
#13 [method] invoke <Rake::Task#invoke(*args)>
#14 [block] block (2 levels) in <top (required)>
#15 [block] block in run <RSpec::Core::Example#run(example_group_instance, reporter)>
#16 [block] block in with_around_and_singleton_context_hooks <RSpec::Core::Example#with_around_and_singleton_context_hooks()>
#17 [block] block in with_around_example_hooks <RSpec::Core::Example#with_around_example_hooks()>
#18 [block] block in run <RSpec::Core::Hooks::HookCollections#run(position, scope, example_or_group)>
#19 [block] block in run_around_example_hooks_for <RSpec::Core::Hooks::HookCollections#run_around_example_hooks_for(example)>
#20 [method] call <RSpec::Core::Example::Procsy#call(*args, &block)>
#21 [block] block (2 levels) in <module:MinitestLifecycleAdapter>
#22 [method] instance_exec <RSpec::Core::Example#instance_exec(*args, &block)>
#23 [method] execute_with <RSpec::Core::Hooks::AroundHook#execute_with(example, procsy)>
#24 [block] block (2 levels) in run_around_example_hooks_for <RSpec::Core::Hooks::HookCollections#run_around_example_hooks_for(example)>
#25 [method] call <RSpec::Core::Example::Procsy#call(*args, &block)>
#26 [block] block (3 levels) in <top (required)>
#27 [method] perform_enqueued_jobs <ActiveJob::TestHelper#perform_enqueued_jobs(?, ?)>
#28 [block] block (2 levels) in <top (required)>
#29 [method] instance_exec <RSpec::Core::Example#instance_exec(*args, &block)>
#30 [method] execute_with <RSpec::Core::Hooks::AroundHook#execute_with(example, procsy)>
#31 [block] block (2 levels) in run_around_example_hooks_for <RSpec::Core::Hooks::HookCollections#run_around_example_hooks_for(example)>
#32 [method] call <RSpec::Core::Example::Procsy#call(*args, &block)>
#33 [block] block in run <RSpec::Retry#run()>
#34 [method] run <RSpec::Retry#run()>
#35 [method] run_with_retry <RSpec::Core::Example::Procsy#run_with_retry(opts=?)>
#36 [block] block (2 levels) in setup <self.setup(UNKNOWN) (undefined method)>
#37 [method] instance_exec <RSpec::Core::Example#instance_exec(*args, &block)>
#38 [method] execute_with <RSpec::Core::Hooks::AroundHook#execute_with(example, procsy)>
#39 [block] block (2 levels) in run_around_example_hooks_for <RSpec::Core::Hooks::HookCollections#run_around_example_hooks_for(example)>
#40 [method] call <RSpec::Core::Example::Procsy#call(*args, &block)>
#41 [method] run_around_example_hooks_for <RSpec::Core::Hooks::HookCollections#run_around_example_hooks_for(example)>
#42 [method] run <RSpec::Core::Hooks::HookCollections#run(position, scope, example_or_group)>
#43 [method] with_around_example_hooks <RSpec::Core::Example#with_around_example_hooks()>
#44 [method] with_around_and_singleton_context_hooks <RSpec::Core::Example#with_around_and_singleton_context_hooks()>
#45 [method] run <RSpec::Core::Example#run(example_group_instance, reporter)>
#46 [block] block in run_examples <RSpec::Core::ExampleGroup.run_examples(reporter)>
#47 [method] run_examples <RSpec::Core::ExampleGroup.run_examples(reporter)>
#48 [method] run <RSpec::Core::ExampleGroup.run(reporter=?)>
#49 [block] block (3 levels) in run_specs <RSpec::Core::Runner#run_specs(example_groups)>
#50 [block] block (2 levels) in run_specs <RSpec::Core::Runner#run_specs(example_groups)>
#51 [method] with_suite_hooks <RSpec::Core::Configuration#with_suite_hooks()>
#52 [block] block in run_specs <RSpec::Core::Runner#run_specs(example_groups)>
#53 [method] report <RSpec::Core::Reporter#report(expected_example_count)>
#54 [method] run_specs <RSpec::Core::Runner#run_specs(example_groups)>
#55 [method] run <RSpec::Core::Runner#run(err, out)>
#56 [method] run <RSpec::Core::Runner.run(args, err=?, out=?)>
#57 [method] invoke <RSpec::Core::Runner.invoke()>
#58 [top] <top (required)>
#59 [eval] <main>
#60 [main] <main>
编辑 2:添加了更多信息
我已经检查过如果我这样放置会发生什么binding.pry
(以及在 rake 任务中)
it "creates users" do
expect(AppClient).to receive(:post).with(some_url, some_data, some_header)
binding.pry # no1 before rake task invokation
Rake::Task['after_party:create_users_on_another_app'].invoke
binding.pry # no3 after rake task invokation
puts "DONE"
end
下面是派对耙任务代码
namespace :after_party do
desc 'Deployment task: create_users_on_another_app'
task create_users_on_another_app: :environment do
...some code
binding.pry # no2 inside the task
AppClient.post(some_url, some_payload, some_header)
...some more code
AfterParty::TaskRecord.create version: '20190620160110'
end
end
end
并且输出是代码执行停止在no1
,然后我们进入 rake 任务并停止在no2
,之后任务再次运行(所以再次停止在no2
),然后它停止在no3
解决方案
这取决于你如何在测试中加载你的 rake 任务
# File1
dscribe 'some test 1' do
before do
Dir.glob('lib/tasks/*.rake').each { |r| load r }
end
...
end
# File2
dscribe 'some test 2' do
before do
Dir.glob('lib/tasks/*.rake').each { |r| load r }
end
...
end
在这两个文件的一次测试运行中不太好。Rake 似乎注册了两次 rake 任务。您需要注意 rake 任务只需注册一次,如下所示:
RSpec.configure do |config|
confige.before :suite do
Dir.glob('lib/tasks/*.rake').each { |r| load r }
end
end
这应该有效,因为测试注册只进行一次。或以某种方式使用require
. require
检查文件是否已注册。
推荐阅读
- javascript - 使用递归检查元素是否为数组
- ruby-on-rails - Symbol 与 100 的比较失败
- date - 如何找到前几周的日期?
- r - 删除R中表格中的重复日期
- kubernetes - 有没有办法检测 Helm Chart 部署的资源所做的更改
- android - 如何区分多个用户的指纹?
- amazon-web-services - AWS CodeArtifact:mvn deploy:deploy-file 无法部署工件:无法传输工件 401 Unauthorized
- c++ - cpp-httplib https 服务器无法在 Linux 上运行
- pyspark - 将列传递给函数,其中列可以为空
- excel - VBA 从工作表中导出/保存 PDF 仅选择非空白单元格