Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you mock/stub backtick system calls in Rspec?

Tags:

ruby

rspec

I have a method that uses backticks but the stub is not working for it. It is pulling the result of ls:

class TestHelper
  def self.test_method
    `ls`
  end
end

rspec test:

describe TestHelper do
  describe '.test_method' do
    subject { described_class.test_method }
    before { Kernel.stub(:`).and_return("test_dir") }
    it { expect(subject).to eql("test_dir") } 
  end
end
like image 773
perseverance Avatar asked Jun 12 '14 22:06

perseverance


3 Answers

TestHelper receives it, and then delegates that to Kernel. So, stub TestHelper:

describe TestHelper do
  describe '.test_method' do
    subject { described_class.test_method }
    before { allow(described_class).to receive(:`).and_return("test_dir") }
    it { is_expected.to eql("test_dir") } 
  end
end
like image 111
Ramon Tayag Avatar answered Nov 19 '22 20:11

Ramon Tayag


Wrap ls in a method, and stub that method out.

def ls
  `ls`
end

Stub this method to return whatever you'd like. You don't need to test the system call.

like image 35
dysruption Avatar answered Nov 19 '22 19:11

dysruption


Since your TestHelper class inherits from Object, it has a backtick method as well because "[t]he Kernel module is included by class Object, so its methods are available in every Ruby object.".

If you want to test that TestHelper.test_method calls the Kernel#` method with 'ls' as an argument, rather than what it actually returns (I'm assuming this because that's all your method does: it doesn't use the value returned from ls in any other operation. If it did, stubbing out that value to use in the other operations would make sense) you can do away with testing the value of a stubbed out method and just test that the expected backtick method is called on your own TestHelper class. However, in case you still want to use stubbed method calls, I've put both ways of potentially testing this below:

describe TestHelper do
  describe '.test_method' do
    describe 'called methods' do
      it 'calls the `ls` command' do
        expect(described_class).to receive(:`).with('ls')
        described_class.test_method
      end
    end

    describe 'result' do
      let(:test_method) { described_class.test_method }
      let(:directories) { 'test_dir' }

      before do
        allow(described_class).to receive(:`).with('ls').and_return(directories)
      end

      it 'equals the expected directories' do
        expect(test_method).to eq(directories)
      end
    end
  end
end
like image 3
Paul Fioravanti Avatar answered Nov 19 '22 20:11

Paul Fioravanti