Back to Repositories

Testing Apache Log Formatter Implementation in HTTParty

This test suite validates the Apache-style logging formatter functionality in HTTParty’s logger module. It ensures proper formatting of HTTP request logs with timestamps, status codes, and content length information.

Test Coverage Overview

The test suite comprehensively covers the ApacheFormatter class functionality, focusing on log message formatting for HTTP requests.

  • Tests basic log format with HTTP method, URL, and status code
  • Verifies handling of Content-Length headers
  • Covers edge cases with parsed responses
  • Tests integration with logger interface

Implementation Analysis

The testing approach utilizes RSpec’s powerful mocking capabilities to isolate the formatter logic.

Key patterns include:
  • Use of let blocks for test setup
  • Double objects to mock HTTP requests and responses
  • Expectation setting for logger behavior
  • Context-based test organization

Technical Details

Testing infrastructure includes:
  • RSpec as the testing framework
  • Double objects for dependency isolation
  • Time formatting utilities
  • Mock HTTP request/response objects
  • Custom formatter implementation

Best Practices Demonstrated

The test suite exemplifies several testing best practices in Ruby.

  • Proper test isolation using doubles
  • Clear context separation
  • Focused test cases
  • Descriptive test naming
  • Efficient setup using let blocks
  • Edge case coverage

jnunemaker/httparty

spec/httparty/logger/apache_formatter_spec.rb

            
require 'spec_helper'

RSpec.describe HTTParty::Logger::ApacheFormatter do
  let(:subject) { described_class.new(logger_double, :info) }
  let(:logger_double) { double('Logger') }
  let(:request_double) { double('Request', http_method: Net::HTTP::Get, path: "http://my.domain.com/my_path") }
  let(:request_time) { Time.new.strftime("%Y-%m-%d %H:%M:%S %z") }

  before do
    expect(logger_double).to receive(:info).with(log_message)
  end

  describe "#format" do
    let(:log_message) { "[HTTParty] [#{request_time}] 302 \"GET http://my.domain.com/my_path\" - " }

    it "formats a response in a style that resembles apache's access log" do
      response_double = double(
        code: 302,
        :[] => nil
      )

      subject.format(request_double, response_double)
    end

    context 'when there is a parsed response' do
      let(:log_message) { "[HTTParty] [#{request_time}] 200 \"GET http://my.domain.com/my_path\" 512 "}

      it "can handle the Content-Length header" do
        # Simulate a parsed response that is an array, where accessing a string key will raise an error. See Issue #299.
        response_double = double(
            code: 200,
            headers: { 'Content-Length' => 512 }
        )
        allow(response_double).to receive(:[]).with('Content-Length').and_raise(TypeError.new('no implicit conversion of String into Integer'))

        subject.format(request_double, response_double)
      end
    end
  end
end