Testing invocation of external executables, %x{}, `
If you ever found yourself trying to write tests for code that invokes an external executable, such as:
class Beef < ActiveRecord::Base
def diskspace(flags = 'sh')
`du -#{flags} .`.split.first
end
end
…and wondered how to write a spec that ensures the du command is called with the right options, you might have tried something like:
before do
@beef = Beef.new
end
it "has diskspace with humanized multipliers" do
Kernel.should_receive(:`).with("du -h .")
@beef.diskspace('h')
end
That doesn’t work.
After some headscratching and calls for help on the ruby-talk mailing list, I learned how the Kernel#` method is not being called directly. The Ruby object hierarchy has Object at the top-level, and thus all your objects eventually descends from Object. As Object mixes in Kernel, all your objects have all the methods defined in that module, so it’s not Kernel that receives your call to “`”, but it’s the current ‘self’. In the example above it’s the @beef instance.
Consider:
class Sheep
def mytick(arg)
puts "tickety-tick: #{arg.inspect}"
end
alias :"`" :mytick
def tick_it!
`cheese`
end
end
Sheep.new.tick_it!
$ ruby sheep.rb
tickety-tick: "cheese"
So, to test the original code, here’s the right way:
it "has diskspace with humanized multipliers" do
@beef.should_receive(:`).with("du -h .")
@beef.diskspace('h')
end
All of the above also applies to the “%x[]“-syntax (just an alias for Kernel#`).
Kudos to Brian Chandler for helping out on this, and happy hacking!
