Question

How would be the correct way to mock or override the Kernel.system method so that when called with:

system("some command")

instead of executing the command, it executes some predefined code?

I tried adding the following to my Test class:

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

But it did not work as expected, instead, the system call was run when executing a test.

Was it helpful?

Solution 2

If you are talking about unit tests and use Rspec, you should be able to do it like this:

Kernel.should_receive(:system)

or a little more loose:

Kernel.stub(:system)

More info: https://www.relishapp.com/rspec/rspec-mocks/v/2-13/docs/message-expectations/expect-a-message

OTHER TIPS

In some cases doing expect(Kernel).to receive(:system) is not enough.

Consider this example:

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

It will not work. This is because Kernel is a module and Object (parent class) is mixes in the Kernel module, making all Kernel method available in "global" scope.

This is why proper tests should looks like this:

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

Since this question was asked, RSpec 3 has come out with a new syntax, where you would write this:

expect(Kernel).to receive(:system)

If your code checks whether or not the system call was a success, you can specify the result like this:

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

The loose version:

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

If it is within a class, kernel is mixed in. So you would just mock it as if it was part of the object.

E.g.

expect(subject).to receive(:system).and_return(foo)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top