The letter A styled as Alchemists logo. lchemists Syndication Icon

Putin's War on Ukraine - Watch President Zelenskyy's speech and help Ukraine fight against the senseless cruelty of a dictator!

Published May 15, 2022 Updated May 28, 2022
HTTP Fake Icon

HTTP Fake

0.0.0

HTTP Fake is a companion to the HTTP gem when you want a convenient way to test HTTP requests by swapping out your real HTTP client with this fake HTTP client. Using a fake allows you to speed up and simplify your test suite by answering fake responses without hitting a live API. You’ll still want to test against a live API, eventually, within your integration tests but at a lower level, like your unit tests, you can use this gem instead. This gem is particularly useful when using Dependency Injection, especially when coupled with the Auto Injector gem.

Features

  • Provides a fake HTTP client as a testing companion to the HTTP gem.

  • Supports the following HTTP verbs: CONNECT, DELETE, GET, HEAD, OPTIONS, PATCH, POST, PUT, and TRACE.

  • Uses a simple DSL for defining HTTP endpoints, headers, bodies, and statuses.

  • Works well with objects that use Dependency Injection.

  • Speeds up your test suite when you don’t need a live API.

Requirements

Setup

To install within an existing project, run:

bundle add http-fake

You’ll want to ensure this gem is part of your test group since it’s only meant to aid in writing specs.

Usage

This gem works with any test framework and, for demonstration purposes, we’ll assume you’re using RSpec. You can adapt these examples to your test framework of choice. A simple spec might look the this:

RSpec.describe Endpoint do
  subject(:endpoint) { described_class.new http: }

  let :http do
    HTTP::Fake::Client.new do
      get "/customers" do
        headers["Content-Type"] = "application/json"
        status 200

        <<~JSON
          {
            "customers": [
              {"name": "Jill Smith"}
            ]
          }
        JSON
      end
    end
  end

  describe "#customers" do
    it "answers customers array when successful" do
      response = endpoint.customers
      expect(response.parse).to eq(customers: [{name: "Jill Smith"}])
    end
  end
end

As you can see, our fake http client has been defined and injected into our endpoint subject. When the fake is defined, the path, headers, status, and body are registered as well. This allows the fake to match against your real implementation’s URL path and swap out making a real HTTP call with the canned response defined by the fake. When asking the endpoint for its customers, we get back the response as defined by the fake with all of the normal capabilities as if we were using the real HTTP client. This works because this gem uses Mustermann for pattern matching against the routes you define. This means you can defined routes that are explicit — as shown above — or fuzzy based on your testing needs. You can also define multiple endpoints for the same fake in case your implementation needs to test multiple endpoints at once. Example:

let :http do
  HTTP::Fake::Client.new do
    connect("/") { status 200 }

    head("/") { status 200 }
    options("/") { status 204 }

    get "/customers" do
      headers["Content-Type"] = "application/json"
      status 200

      <<~JSON
        {
          "customers": [
            {"name": "Jill Smith"}
          ]
        }
      JSON
    end

    post "/customers" do
      headers["Content-Type"] = "application/json"
      status 201
      {}
    end

    put "/customers/1" do
      headers["Content-Type"] = "application/json"
      status 200
    end

    patch "/customers/1" do
      headers["Content-Type"] = "application/json"
      status 200
    end

    delete("/customers/1") { status 204 }
    trace("/") { status 200 }
  end
end

Lastly, in the examples above, I’ve been showing how you can work with JSON responses but you might want to use other MIME types. For example, XML:

HTTP::Fake::Client.new do
  get "/customers" do
    headers["Content-Type"] = "application/xml"
    status 200

    <<~XML
      <customer>
        <id>1</id>
        <name>Jill Smith</name>
      </customer>
    XML
  end
end

Plain text would work too:

HTTP::Fake::Client.new do
  get "/customers" do
    headers["Content-Type"] = "text/plain"
    status 200

    "1 - Jill Smith"
  end
end

Since you have the ability to define your own headers and status codes, you can also test failure response behavior as well. I’ll leave that up to you to explore and experiment with further.

Development

Clone the repository and then run:

bin/setup

You can also use the IRB console for direct access to all objects:

bin/console

Tests

To test, run:

bundle exec rake

Credits