Mocking HTTP in practice
Use the responses library to intercept requests calls in tests — assert the right URL was called, return fake JSON, and test your error-handling code with a simulated 500.
- Use responses.activate and responses.add to mock a GET request returning JSON
- Assert that exactly the right URL was called and with the right parameters
- Test error-handling code by registering a 500 response
The previous lesson explained why responses is the right tool for unit-testing
HTTP-dependent pipeline code. Here you will build and test a small fetch_records
function that has both a happy path and an error path.
Because the responses library is not available in the in-browser runtime, the
demo below simulates its core behaviour using unittest.mock. The API and
assertions are identical to what you would write with the real library — swap the
import and decorator to use it in your own test files.
Using the real responses library
In your actual test file, replace the mock with responses:
import responses
import requests
def fetch_records(url: str) -> list:
resp = requests.get(url, timeout=10)
resp.raise_for_status()
return resp.json()
@responses.activate
def test_fetch_records_happy_path():
responses.add(
responses.GET,
"https://api.example.com/records",
json=[{"id": 1, "name": "alpha"}, {"id": 2, "name": "beta"}],
status=200,
)
result = fetch_records("https://api.example.com/records")
assert len(result) == 2
assert len(responses.calls) == 1
assert responses.calls[0].request.url == "https://api.example.com/records"
@responses.activate
def test_fetch_records_500_raises():
responses.add(
responses.GET,
"https://api.example.com/records",
status=500,
)
try:
fetch_records("https://api.example.com/records")
assert False, "Expected an exception"
except Exception as exc:
assert "500" in str(exc)By default, responses raises ConnectionError for any URL that is not
registered. This is a feature: it prevents your code from silently hitting live
endpoints during a test run. If you need to allow passthrough for specific URLs,
use responses.add_passthrough(pattern).
Asserting request details
responses.calls gives you the full request history. You can assert headers and
request body:
assert responses.calls[0].request.headers["Authorization"] == "Bearer test-token"
assert json.loads(responses.calls[0].request.body) == {"filter": "active"}This matters for testing authentication flows: verify that your code adds the
correct Authorization header rather than trusting that it "probably" does.
Where to go next
Next: lab — test suite — combine filesystem mocking, HTTP mocking, and error path testing into a complete test suite covering every function in a pipeline script.
Mocking HTTP
Real API calls in tests are slow, costly, and non-deterministic. Understand the three strategies for mocking HTTP — and why the responses library wins for most unit tests.
Lab: test suite
Write a complete test suite for a pipeline script — covering config loading, data transformation, mocked HTTP, file output, and error paths.