如何测试来自 rake 任务的系统调用

How to test system calls from the rake task

假设我有一个非常简单的 Rake 任务:

task :test do
  system "bundle exec rspec spec"
end

我尝试通过打桩 ::Kernel.system 方法调用来测试它:

describe "test" do

  before { allow(::Kernel).to receive(:system) }

  it "runs 'bundle exec rspec spec'" do
    expect(::Kernel).to receive(:system).with "bundle exec rspec spec"
    Rake::Task[:test].invoke
  end
end

但是方法好像一点都不卡。相反,我 运行 进入调用测试套件的无限迭代循环。

它有什么问题,如何正确存根系统调用?

请注意 Kernel 是包含在每个 ruby Object 中的模块。 Kernel#system 是实例方法(不是 class 方法)。

一个解决方案(尽管 discouraged by rspec maintainers)是使用 "Any instance":

it "runs 'bundle exec rspec spec'" do
  expect_any_instance_of(Kernel).to receive(:system).with "bundle exec rspec spec"
  Rake::Task[:test].invoke
end

为了使用常规 expectallow,您需要接收消息的对象的实际 实例 。对于 Rake 任务,这将很麻烦(尽管并非不可能 - 参见 this question)- 它们在顶层上下文中执行。

我建议您将 system 调用封装到实用程序 class 方法和 expect 方法中。这将使测试更容易,并且您可以使用明确的 classes 和实例。