Specing exit codes

I am writing a small ruby script that will be accepting input from
postfix’s pipe command (ie, not running via the shell, directly
executing).

One of the things I need to do it spec the exit codes to make sure I
am returing the correct exit codes for each condition as Postfix will
then return SMTP errors as appropriate.

I have two files that concern this bit of the program, init.rb and
init_spec.rb.

init.rb right now looks like this:

class Init
exit 1
end

init_spec.rb looks like this:

require ‘spec’
require ‘systemu’
require ‘init’

describe Init do
it “should exit on status code 1 without parameters”
command = “ruby mail_dump/init.rb” # not portable
status, stdout, stderr = systemu command
status.should == # what do I put here?
end
end

I have tried a number of things, from trying to stub exit to aliasing
kernel.exit to something else and replacing it… all without joy.

The spec runs and hits the “exit 1” in init.rb and does what it is
mean to do… exit. But that also exits RSpec and so the test is
never run!

The only thing I found DID work is if I alias Kernel.exit inside the
init.rb file to “real_exit” and then redefine Kernel exit like so:

class Object
module Kernel
alias real_exit exit
def exit(arg)
return true if arg == 1
end
end
end

and then test exit by mocking it and making sure it returns true…
but a spec that has to modify the test code isn’t going to scale too
well… and this doesn’t seem right.

Has anyone else had this problem? How did you solve it?

thanks…

Mikel

On Oct 6, 2007, at 11:31 PM, Mikel L. wrote:

require ‘systemu’

class Object
well… and this doesn’t seem right.

Has anyone else had this problem? How did you solve it?

I had a similar problem a while back. Aslak tipped me off to
dependency injection. Something like this:

describe Init do
before :each do
@kernel = mock(Kernel)
@kernel.stub!(:exit).and_return 1
end

it “should exit on status code 1 without parameters”
init = Init.new(@kernel)
init.start
init.status.should == 1
end
end

module Init
def start(kernel=Kernel)
kernel.start
end
end

Scott

Hey Scott,

Thanks for the speedy answer… dependency injection is new to me, so
I am getting my head around it all.

I put your solution in and now I am getting:

SystemExit in ‘Init handling exit codes before(:all)’
exit
./init.rb:8:in exit' ./init.rb:8:ininitialize’

SystemExit in ‘Init handling exit codes after(:all)’
exit
./init.rb:8:in exit' ./init.rb:8:ininitialize’

Finished in 0.020305 seconds

26 examples, 2 failures

Which seems on the right path… how do I catch SystemExit?

I don’t have a before :all or after :all defined explicitly…

Regards

Mikel