3

如何正确模拟或覆盖该Kernel.system方法,以便在调用时:

system("some command")

它不执行命令,而是执行一些预定义的代码?

我尝试将以下内容添加到我的测试类中:

module Kernel
    def system
        puts "SYSTEM CALL!!"
    end
end

但它并没有按预期工作,而是在执行测试时运行了系统调用。

4

4 回答 4

11

在某些情况下,这样做expect(Kernel).to receive(:system)是不够的。

考虑这个例子:

foo_component.rb

class FooComponent
  def run
    system('....')
  end
end

foo_component_spec.rb

require 'spec_helper'

describe FooComponent do
  let(:foo_component) { described_class.new }

  describe '#run' do
    it 'does some awesome things' do
      expect(Kernel).to receive(:system).with('....')
      foo_component.run
    end
  end
end

不起作用。这是因为Kernel它是一个模块,并且Object(父类)混合在Kernel模块中,使所有Kernel方法在“全局”范围内可用。

这就是为什么正确的测试应该是这样的:

require 'spec_helper'

describe FooComponent do
  let(:foo_component) { described_class.new }

  describe '#run' do
    it 'does some awesome things' do
      expect(foo_component).to receive(:system).with('....')
      foo_component.run
    end
  end
end
于 2016-07-14T08:13:32.253 回答
6

如果您正在谈论单元测试并使用 Rspec,您应该可以这样做:

Kernel.should_receive(:system)

或者更宽松一点:

Kernel.stub(:system)

更多信息:https ://www.relishapp.com/rspec/rspec-mocks/v/2-13/docs/message-expectations/expect-a-message

于 2013-05-20T18:13:50.043 回答
5

自从提出这个问题以来,RSpec 3 已经出现了一种新的语法,您可以在其中编写:

expect(Kernel).to receive(:system)

如果您的代码检查系统调用是否成功,您可以像这样指定结果:

expect(Kernel).to receive(:system).and_return(true)

宽松版:

allow(Kernel).to receive(:system).and_return(true)
于 2015-01-18T11:36:32.943 回答
4

如果它在一个类中,内核就会混入其中。所以你只需模拟它,就好像它是对象的一部分。

例如

expect(subject).to receive(:system).and_return(foo)
于 2018-11-20T21:33:12.330 回答