2

I've been working with the Mechanize gem a lot recently and would like to incorporate some tests to ensure I am catching the proper errors. What is the proper way to test error handling?

This is my basic method:

def get(str)
  url = format_url(str)
  #puts "sending GET request to: #{url}"
  sleep(0.1)
  @page = Mechanize.new do |a|
    a.user_agent_alias = 'Mac Safari'
    a.open_timeout = 7
    a.read_timeout = 7
    a.idle_timeout = 7
    a.redirect_ok = true
  end.get(url)

rescue Mechanize::ResponseCodeError => e
  puts "#{'Response Error:'.red} #{e}"
rescue SocketError => e
  puts "#{'Socket Error:'.red} #{e}"
rescue Net::OpenTimeout => e
  puts "#{'Connection Timeout:'.red} #{e}"
rescue Errno::ETIMEDOUT => e
  puts "#{'Connection Timeout:'.red} #{e}"
rescue Net::HTTP::Persistent::Error
  puts "#{'Connection Timeout:'.red} read timeout, too many resets."
end

And this is the start to tests for handling errors:

class TestErrorHandling < Mechanize::TestCase
  context 'Example when sending a GET request' do
    should 'rescue error and return nil' do
      assert_equal nil, Example.get('http://localhost/pagethatdoesntexist')
    end
  end
end

Am I heading in the correct direction? Any insight and/or resources welcome.

binarymason
  • 1,351
  • 1
  • 14
  • 31

3 Answers3

2

This is the link to where I found an answer more in line with what I am asking: https://stackoverflow.com/a/17825110/5381605

describe 'testing' do
  it 'must raise' do
   a = Proc.new {oo.non_existant}
   begin
     a[]
   rescue => e
    end
   e.must_be_kind_of Exception
  end
end
Community
  • 1
  • 1
binarymason
  • 1,351
  • 1
  • 14
  • 31
1

you need to mock the Mechanize class. search other questions how to do

akostadinov
  • 17,364
  • 6
  • 77
  • 85
1

Sort of. You shouldn't test dependent libraries again in your application. It's enough to catch the Net::HTTP::Persistent::Error without ensuring the underlying functionality is working. Well written gems should provide their own tests, and you should be able to access those tests as needed by testing that gem (Mechanize, for example).

You could mock for those errors, but you should be judicious. Here is some code to mock an SMTP connection

 class Mock
    require 'net/smtp'

    def initialize( options )
      @options = options
      @username = options[:username]
      @password = options[:password]
      options[:port] ? @port = options[:port] : @port = 25
      @helo_domain = options[:helo_domain]
      @from_addr = options[:from_address]
      @from_domain = options[:from_domain]

      #Mock object for SMTP connections
      mock_config = {}
      mock_config[:address] = options[:server]
      mock_config[:port] = @port

      @connection = RSpec::instance_double(Net::SMTP, mock_config)

      allow(@connection).to receive(:start).and_yield(@connection)
      allow(@connection).to receive(:send_message).and_return(true)
      allow(@connection).to receive(:started?).and_return(true)
      allow(@connection).to receive(:finish).and_return(true)
    end
    #more stuff here
 end

I don't see you testing for any custom errors which would make more sense here. For example, you might test for url-unfriendly characters in your parameter and rescue from that. In that case, your test would offer something explicit.

 expect(get("???.net")).to raise_error(CustomError)
jjk
  • 536
  • 7
  • 15
  • @jjk thanks for your answer. Some background to this is my crawler has gotten all types of errors in the past, whether it be trying to reach a page that doesn't exist or simply a connection timeout. Mechanize raises each of the errors appropriately, I want to test the handling. – binarymason Oct 14 '15 at 20:17
  • 1
    so if you need to be explicit, you would create a mock object relying on each of those underlying objects. Then you can deal with them to be raised, or whatever. You notice that I am using rspec's instance double to create an interface that I can use. Then I can reference that in my mock object's instance. If this is helpful please mark this answer as correct. – jjk Oct 14 '15 at 20:25
  • Thanks for leading me in the right direction, @jjk. Marking solved. – binarymason Oct 15 '15 at 09:30