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/
On Mon, Apr 21, 2008 at 8:03 AM, Jamie D [email protected]
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
On Mon, Apr 21, 2008 at 8:03 AM, Jamie D [email protected]
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
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