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 Lindsaar wrote:> 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?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: 1) SystemExit in ''Init handling exit codes before(:all)'' exit ./init.rb:8:in `exit'' ./init.rb:8:in `initialize'' 2) SystemExit in ''Init handling exit codes after(:all)'' exit ./init.rb:8:in `exit'' ./init.rb:8:in `initialize'' 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 On 10/7/07, Scott Taylor <mailing_lists at railsnewbie.com> wrote:> > On Oct 6, 2007, at 11:31 PM, Mikel Lindsaar wrote: > > > 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? > > 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 > > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users >