The project is in a healthy, maintained state
Stub HTTP requests in tests with a fluent API for matching methods, URLs, headers, and bodies. Includes request recording and scoped isolation.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Dependencies
 Project Readme

philiprehberger-http_mock

Tests Gem Version Last updated

Lightweight HTTP request stubbing for tests

Requirements

  • Ruby >= 3.1

Installation

Add to your Gemfile:

gem "philiprehberger-http_mock"

Or install directly:

gem install philiprehberger-http_mock

Usage

require "philiprehberger/http_mock"

Philiprehberger::HttpMock.stub(:get, "https://api.example.com/users")
  .to_return(status: 200, body: '{"users":[]}')

response = Philiprehberger::HttpMock.request(:get, "https://api.example.com/users")
response.status  # => 200
response.body    # => '{"users":[]}'

POST with Body Matching

Philiprehberger::HttpMock.stub(:post, "https://api.example.com/users")
  .with(body: '{"name":"Alice"}')
  .to_return(status: 201, body: '{"id":1}')

Header Matching

Philiprehberger::HttpMock.stub(:get, "https://api.example.com/data")
  .with(headers: { "Authorization" => "Bearer token123" })
  .to_return(status: 200, body: "secret")

Response Sequences

Philiprehberger::HttpMock.stub(:get, "https://api.example.com/flaky")
  .to_return_in_sequence([
    { status: 503, body: "unavailable" },
    { status: 200, body: "ok" }
  ])

Philiprehberger::HttpMock.request(:get, "https://api.example.com/flaky").status  # => 503
Philiprehberger::HttpMock.request(:get, "https://api.example.com/flaky").status  # => 200
Philiprehberger::HttpMock.request(:get, "https://api.example.com/flaky").status  # => 200 (repeats last)

Callback Responses

Philiprehberger::HttpMock.stub(:post, "https://api.example.com/echo")
  .to_return { |request| { status: 200, body: request.body.upcase } }

response = Philiprehberger::HttpMock.request(:post, "https://api.example.com/echo", body: "hello")
response.body  # => "HELLO"

Stub Verification

stub = Philiprehberger::HttpMock.stub(:get, "https://api.example.com/data")
  .to_return(status: 200)

Philiprehberger::HttpMock.request(:get, "https://api.example.com/data")

stub.called?     # => true
stub.call_count  # => 1

Philiprehberger::HttpMock.verify!  # raises UnmatchedStubError if any stub was never called

Request Recording

Philiprehberger::HttpMock.stub(:get, "https://api.example.com/data").to_return(status: 200)
Philiprehberger::HttpMock.request(:get, "https://api.example.com/data")

requests = Philiprehberger::HttpMock.requests
requests.length      # => 1
requests.first.url   # => "https://api.example.com/data"

Scoped Isolation

Philiprehberger::HttpMock.scope do
  Philiprehberger::HttpMock.stub(:get, "https://api.example.com/temp")
    .to_return(status: 200)

  # Stubs are automatically cleaned up after the block
end

API

HttpMock

Method Description
.stub(method, url) Create a request stub, returns a chainable stub definition
.request(method, url, body:, headers:) Simulate a request against registered stubs
.requests Get all recorded requests
.verify! Raise UnmatchedStubError if any stub was never called
.reset! Clear all stubs and recorded requests
.scope { ... } Execute a block with isolated stubs

StubDefinition

Method Description
#with(body:, headers:) Add matching constraints for body and/or headers
#to_return(status:, body:, headers:) Set the response to return
#to_return { |request| ... } Set a dynamic response callback
#to_return_in_sequence(responses) Set an ordered sequence of responses
#call_count Number of times this stub has been matched
#called? Whether this stub has been matched at least once

Development

bundle install
bundle exec rspec
bundle exec rubocop

Support

If you find this project useful:

Star the repo

🐛 Report issues

💡 Suggest features

❤️ Sponsor development

🌐 All Open Source Projects

💻 GitHub Profile

🔗 LinkedIn Profile

License

MIT