Back to Repositories

Testing Error Handling Implementation in Geocoder

This test suite validates error handling capabilities in the Geocoder gem, focusing on various network and parsing errors that may occur during geocoding operations. The tests ensure proper handling of timeouts, parse errors, socket errors, and connection issues across different geocoding service providers.

Test Coverage Overview

The test suite provides comprehensive coverage of error handling scenarios in the Geocoder gem.

Key areas tested include:
  • Timeout error handling across all HTTP-based services
  • Response parsing errors for specific providers (FreeGeoIP, Google, IPData)
  • Network-related errors including socket errors and connection issues
  • Configuration-based error raising behavior

Implementation Analysis

The testing approach employs Ruby’s unit testing framework with systematic validation of error scenarios. Each test case follows a pattern of configuring the geocoder, setting up the test condition, and verifying the expected error handling behavior.

The implementation uses service-specific test cases combined with loops over all HTTP-based services for comprehensive coverage.

Technical Details

Testing tools and configuration:
  • Ruby’s built-in test framework
  • Custom GeocoderTestCase class for shared functionality
  • Configuration-based error handling using Geocoder.configure
  • Service-specific API key management
  • Error simulation through query parameters

Best Practices Demonstrated

The test suite exemplifies several testing best practices in Ruby.

Notable practices include:
  • Proper test isolation through teardown methods
  • Comprehensive error type coverage
  • Consistent test naming conventions
  • Modular test organization
  • Effective use of assertion methods
  • Clear separation of configuration and test logic

alexreisner/geocoder

test/unit/error_handling_test.rb

            
# encoding: utf-8
require 'test_helper'

class ErrorHandlingTest < GeocoderTestCase

  def teardown
    Geocoder.configure(:always_raise => [])
  end

  def test_does_not_choke_on_timeout
    silence_warnings do
      Geocoder::Lookup.all_services_with_http_requests.each do |l|
        Geocoder.configure(:lookup => l)
        set_api_key!(l)
        assert_nothing_raised { Geocoder.search("timeout") }
      end
    end
  end

  def test_always_raise_response_parse_error
    Geocoder.configure(:always_raise => [Geocoder::ResponseParseError])
    [:freegeoip, :google, :ipdata_co].each do |l|
      lookup = Geocoder::Lookup.get(l)
      set_api_key!(l)
      assert_raises Geocoder::ResponseParseError do
        lookup.send(:results, Geocoder::Query.new("invalid_json"))
      end
    end
  end

  def test_never_raise_response_parse_error
    [:freegeoip, :google, :ipdata_co].each do |l|
      lookup = Geocoder::Lookup.get(l)
      set_api_key!(l)
      silence_warnings do
        assert_nothing_raised do
          lookup.send(:results, Geocoder::Query.new("invalid_json"))
        end
      end
    end
  end

  def test_always_raise_timeout_error
    Geocoder.configure(:always_raise => [Timeout::Error])
    Geocoder::Lookup.all_services_with_http_requests.each do |l|
      lookup = Geocoder::Lookup.get(l)
      set_api_key!(l)
      assert_raises Timeout::Error do
        lookup.send(:results, Geocoder::Query.new("timeout"))
      end
    end
  end

  def test_always_raise_socket_error
    Geocoder.configure(:always_raise => [SocketError])
    Geocoder::Lookup.all_services_with_http_requests.each do |l|
      lookup = Geocoder::Lookup.get(l)
      set_api_key!(l)
      assert_raises SocketError do
        lookup.send(:results, Geocoder::Query.new("socket_error"))
      end
    end
  end

  def test_always_raise_connection_refused_error
    Geocoder.configure(:always_raise => [Errno::ECONNREFUSED])
    Geocoder::Lookup.all_services_with_http_requests.each do |l|
      lookup = Geocoder::Lookup.get(l)
      set_api_key!(l)
      assert_raises Errno::ECONNREFUSED do
        lookup.send(:results, Geocoder::Query.new("connection_refused"))
      end
    end
  end

  def test_always_raise_host_unreachable_error
    Geocoder.configure(:always_raise => [Errno::EHOSTUNREACH])
    Geocoder::Lookup.all_services_with_http_requests.each do |l|
      lookup = Geocoder::Lookup.get(l)
      set_api_key!(l)
      assert_raises Errno::EHOSTUNREACH do
        lookup.send(:results, Geocoder::Query.new("host_unreachable"))
      end
    end
  end
end