如何正确模拟或覆盖该Kernel.system
方法,以便在调用时:
system("some command")
它不执行命令,而是执行一些预定义的代码?
我尝试将以下内容添加到我的测试类中:
module Kernel
def system
puts "SYSTEM CALL!!"
end
end
但它并没有按预期工作,而是在执行测试时运行了系统调用。
在某些情况下,这样做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
如果您正在谈论单元测试并使用 Rspec,您应该可以这样做:
Kernel.should_receive(:system)
或者更宽松一点:
Kernel.stub(:system)
更多信息:https ://www.relishapp.com/rspec/rspec-mocks/v/2-13/docs/message-expectations/expect-a-message
自从提出这个问题以来,RSpec 3 已经出现了一种新的语法,您可以在其中编写:
expect(Kernel).to receive(:system)
如果您的代码检查系统调用是否成功,您可以像这样指定结果:
expect(Kernel).to receive(:system).and_return(true)
宽松版:
allow(Kernel).to receive(:system).and_return(true)
如果它在一个类中,内核就会混入其中。所以你只需模拟它,就好像它是对象的一部分。
例如
expect(subject).to receive(:system).and_return(foo)