NAME

Test::HTTP::Scenario - Deterministic record/replay of HTTP interactions for test suites

VERSION

Version 0.01

SYNOPSIS

use Test::Most;
use Test::HTTP::Scenario qw(with_http_scenario);

with_http_scenario(
    name    => 'get_user_basic',
    file    => 't/fixtures/get_user_basic.yaml',
    mode    => 'replay',
    adapter => 'LWP',
    sub {
        my $user = $client->get_user(42);
        cmp_deeply($user, superhashof({ id => 42 }));
    },
);

DESCRIPTION

Test::HTTP::Scenario lets you test HTTP-based code without ever hitting the real network, by recording real interactions once and replaying them forever. It provides a deterministic record/replay mechanism for HTTP-based test suites. It allows you to capture real HTTP interactions once (record mode) and replay them later without network access (replay mode). This makes API client tests fast, hermetic, and fully deterministic.

Adapters provide the glue to specific HTTP client libraries such as LWP. Serializers control how fixtures are stored on disk.

MODES

record

Real HTTP requests are executed. Each request/response pair is normalized and appended to the fixture. The fixture file is written at the end of run().

replay

No real HTTP requests are made. Requests are matched against the fixture in order, and responses are reconstructed from stored data.

STRICT MODE

If strict => 1 is enabled, replay mode requires that all recorded interactions are consumed. If the callback returns early, run() croaks with a strict-mode error.

DIFFING

If diffing => 1 (default), mismatched requests produce a detailed diff showing expected and actual method, URI, and normalized request structures.

ADAPTERS

Adapters implement:

Available adapters:

You may also supply a custom adapter object.

SERIALIZERS

Serializers implement encoding and decoding of fixture files.

Available serializers:

USING RECORD AND REPLAY IN REAL-WORLD APPLICATIONS

This section describes the recommended workflow for using Test::HTTP::Scenario in a real-world test suite. The goal is to capture real HTTP traffic once (record mode) and then replay it deterministically in all subsequent test runs (replay mode).

Overview

Record/replay is designed for API client libraries that normally make live HTTP requests. In record mode, the module performs real network calls and stores normalized request/response pairs in a fixture file. In replay mode, the module prevents all network access and returns synthetic responses reconstructed from the fixture.

This allows your test suite to:

Typical Workflow

Step 1: Write your test using with_http_scenario

use Test::Most;
use Test::HTTP::Scenario qw(with_http_scenario);

with_http_scenario(
    name    => 'get_user_flow',
    file    => 't/fixtures/get_user_flow.yaml',
    mode    => $ENV{SCENARIO_MODE} || 'replay',
    adapter => 'LWP',
    sub {
        my $user = MyAPI->new->get_user(42);
        is $user->{id}, 42, 'user id matches';
    },
);

Step 2: Run the test suite in record mode

$ SCENARIO_MODE=record prove -l t/get_user_flow.t

This performs real HTTP requests and writes the fixture file:

t/fixtures/get_user_flow.yaml

Step 3: Commit the fixture file to version control

The fixture becomes part of your test assets. It should be treated like any other test data file.

Step 4: Run the test suite normally (replay mode)

$ prove -l t

Replay mode:

No network access is required.

Updating Fixtures

If the API changes or you need to refresh the recorded data, simply delete the fixture file and re-run the test in record mode:

$ rm t/fixtures/get_user_flow.yaml
$ SCENARIO_MODE=record prove -l t/get_user_flow.t

Example: Multi-Step API Flow

Record mode captures each request in order:

with_http_scenario(
    name    => 'create_and_fetch',
    file    => 't/fixtures/create_and_fetch.yaml',
    mode    => $ENV{SCENARIO_MODE} || 'replay',
    adapter => 'LWP',
    sub {
        my $api = MyAPI->new;

        my $id = $api->create_user({ name => 'Alice' });
        my $user = $api->get_user($id);

        is $user->{name}, 'Alice';
    },
);

Replay mode enforces the same sequence, ensuring your client behaves correctly across multiple calls.

Notes

METHODS

new

Construct a new scenario object.

Purpose

Initializes a scenario with a name, fixture file, mode, adapter, and serializer. Loads adapter and serializer classes and binds the adapter to the scenario.

Arguments

Returns

A new Test::HTTP::Scenario object.

Side Effects

Loads adapter and serializer classes dynamically. Binds the adapter to the scenario.

Notes

The adapter object persists across calls to run().

run

Execute a coderef under scenario control.

Purpose

Installs adapter hooks, loads fixtures in replay mode, executes the callback, and saves fixtures in record mode. Ensures uninstall and save always occur.

Arguments

Returns

Whatever the coderef returns, preserving list, scalar, or void context.

Side Effects

Notes

Exceptions propagate naturally. Strict mode enforces full consumption of recorded interactions.

with_http_scenario

Convenience wrapper for constructing and running a scenario.

Purpose

Creates a scenario object from key/value arguments and immediately executes run() with the supplied coderef.

Arguments

Key/value pairs identical to new, followed by a coderef.

Returns

Whatever the coderef returns.

Side Effects

Constructs a scenario and installs adapter hooks during execution.

Notes

The final argument must be a coderef.

handle_request

Handle a single HTTP request in record or replay mode.

Purpose

In record mode, performs the real HTTP request and stores the normalized request and response. In replay mode, matches the incoming request against stored interactions and returns a synthetic response.

Arguments

Returns

Side Effects

Notes

Matching is currently based on method and URI only. Diffing mode produces detailed mismatch diagnostics.

AUTHOR

Nigel Horne, <njh at nigelhorne.com>

BUGS

SEE ALSO

REPOSITORY

https://github.com/nigelhorne/Test-HTTP-Scenario

SUPPORT

This module is provided as-is without any warranty.

Please report any bugs or feature requests to bug-test-http-scenario at rt.cpan.org, or through the web interface at http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Test-HTTP-Scenario. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.

You can find documentation for this module with the perldoc command.

perldoc Test::HTTP::Scenario

You can also look for information at:

LICENCE AND COPYRIGHT

Copyright 2026 Nigel Horne.

Usage is subject to licence terms.

The licence terms of this software are as follows: