Hi, So I''m stuck again with creating a mock for Net::SSH, I''ve managed to mock the call to Net::SSH.start and yield the Net::SSH mock but I am totally stuck with mocking the session.shell.sync call and will also need to mock the shell.send_command call also. Any help much appreciated. When I run the following spec I get the error: Mock ''Net::SSH'' received unexpected message :shell with (no args) I''ve tried things like @shell = mock(Net::SSH::Service::Shell) but this also gives an error complaining that Service doe snot exist. # test code @connection = Ssh::Remote.new @ssh = mock(Net::SSH) Net::SSH.should_receive(:start).and_yield(@ssh) Net::SSH.should_receive(:shell).and_return(''something'') # library code require ''net/ssh'' module Ssh class Remote def remote_command(server, user, commands=[]) Net::SSH.start(server, user) do |session| shell = session.shell.sync commands.each do |command| out = shell.send_command command[:command] end end end end end
On 21 Apr 2008, at 07:03, Jamie D wrote:> Net::SSH.should_receive(:shell).and_return(''something'')This should be @ssh.should_receive(:shell).and_return(''something'') But actually it will need to return a mock with :sync stubbed for the line: shell = session.shell.sync Ashley -- http://www.patchspace.co.uk/ http://aviewfromafar.net/
On Mon, Apr 21, 2008 at 8:03 AM, Jamie D <jam5t3r.lists at gmail.com> wrote:> Hi, > > So I''m stuck again with creating a mock for Net::SSH, I''ve managed to > mock the call to Net::SSH.start and yield the Net::SSH mock but I am > totally stuck with mocking the session.shell.sync call and will also > need to mock the shell.send_command call also. Any help much > appreciated. >Don''t mock APIs you don''t own. http://rubyurl.com/53Y6 Instead - create a thin API around such APIs and have your app use that instead. Now you have an easily mockable API. Also make sure you have end-to-end tests that use Net::SSH without any mocking. Aslak> When I run the following spec I get the error: > Mock ''Net::SSH'' received unexpected message :shell with (no args) > > I''ve tried things like @shell = mock(Net::SSH::Service::Shell) but > this also gives an error complaining that Service doe snot exist. > > # test code > @connection = Ssh::Remote.new > @ssh = mock(Net::SSH) > Net::SSH.should_receive(:start).and_yield(@ssh) > Net::SSH.should_receive(:shell).and_return(''something'') > > # library code > require ''net/ssh'' > > module Ssh > class Remote > > def remote_command(server, user, commands=[]) > Net::SSH.start(server, user) do |session| > shell = session.shell.sync > commands.each do |command| > out = shell.send_command command[:command] > end > end > end > end > end > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users >
On Mon, Apr 21, 2008 at 8:03 AM, Jamie D <jam5t3r.lists at gmail.com> wrote:> Hi, > > So I''m stuck again with creating a mock for Net::SSH, I''ve managed to > mock the call to Net::SSH.start and yield the Net::SSH mock but I am > totally stuck with mocking the session.shell.sync call and will also > need to mock the shell.send_command call also. Any help much > appreciated. >Don''t mock APIs you don''t own. http://rubyurl.com/53Y6 Instead - create a thin API around such APIs and have your app use that instead. Now you have an easily mockable API. Also make sure you have end-to-end tests that use Net::SSH without any mocking. Aslak> When I run the following spec I get the error: > Mock ''Net::SSH'' received unexpected message :shell with (no args) > > I''ve tried things like @shell = mock(Net::SSH::Service::Shell) but > this also gives an error complaining that Service doe snot exist. > > # test code > @connection = Ssh::Remote.new > @ssh = mock(Net::SSH) > Net::SSH.should_receive(:start).and_yield(@ssh) > Net::SSH.should_receive(:shell).and_return(''something'') > > # library code > require ''net/ssh'' > > module Ssh > class Remote > > def remote_command(server, user, commands=[]) > Net::SSH.start(server, user) do |session| > shell = session.shell.sync > commands.each do |command| > out = shell.send_command command[:command] > end > end > end > end > end > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users >
Thanks for the info Aslak, I have rewritten my code like you suggest but have one issue with raising an exception. When I try the code in the console an exception is raised correctly but in my test code I get a message "command did not return expected result" # test describe Ssh, "Remote" do before(:each) do @ssh = mock(Net::SSH) @response = mock(Net::SSH) @connection = Ssh::Remote.new @connection.should_receive(:start).with(''server'', ''root'').and_return(@ssh) @connection.should_receive(:close) @ssh.should_receive(:send_command).with(''ls /'').and_return(@response) @response.should_receive(:stdout).and_return(''a list'') end it "should raise exception if response does not match expected" do @connection.remote_command(''server'', ''root'', [{:command => ''ls /'', :expects => /blah/}]). should raise_error(Ssh::CommandError, ''command did not return expected result'') end end # code exception.rb module Ssh class CommandError < Exception end end # ssh.rb require ''net/ssh'' require ''ssh/exception'' module Ssh class Remote def remote_command(server, user, commands=[]) shell = start(server, user) commands.each do |command| out = shell.send_command command[:command] unless out.stdout =~ command[:expects] or command[:expects].blank? close raise(CommandError.new, ''command did not return expected result'') end end close return true end def start(server, user) @session = Net::SSH.start(server, user) @session.shell.sync end def close() @session.close end end end Thanks Jamie
Fixed it, I was missing the lambda: it "should raise exception if response does not match expected" do lambda{ @connection.remote_command(''server'', ''root'', [{:command => ''ls /'', :expects => /blah/}]) }. should raise_error(Ssh::CommandError, ''command did not return expected result'') end On 21/04/2008, Jamie D <jam5t3r.lists at gmail.com> wrote:> Thanks for the info Aslak, I have rewritten my code like you suggest > but have one issue with raising an exception. When I try the code in > the console an exception is raised correctly but in my test code I get > a message "command did not return expected result" > > # test > describe Ssh, "Remote" do > > before(:each) do > @ssh = mock(Net::SSH) > @response = mock(Net::SSH) > @connection = Ssh::Remote.new > @connection.should_receive(:start).with(''server'', ''root'').and_return(@ssh) > @connection.should_receive(:close) > @ssh.should_receive(:send_command).with(''ls /'').and_return(@response) > @response.should_receive(:stdout).and_return(''a list'') > end > > it "should raise exception if response does not match expected" do > @connection.remote_command(''server'', ''root'', [{:command => ''ls /'', > :expects => /blah/}]). > should raise_error(Ssh::CommandError, ''command did not return > expected result'') > end > > end > > # code exception.rb > module Ssh > class CommandError < Exception > end > end > > # ssh.rb > require ''net/ssh'' > require ''ssh/exception'' > > > module Ssh > class Remote > > def remote_command(server, user, commands=[]) > > shell = start(server, user) > > commands.each do |command| > out = shell.send_command command[:command] > > unless out.stdout =~ command[:expects] or command[:expects].blank? > close > raise(CommandError.new, ''command did not return expected result'') > end > end > close > return true > end > > def start(server, user) > @session = Net::SSH.start(server, user) > @session.shell.sync > end > > def close() > @session.close > end > > end > end > > Thanks > > Jamie >