### Configure HTTPServer with Startup Timeout Source: https://github.com/csernazs/pytest-httpserver/blob/master/doc/howto.md Override the `make_httpserver` fixture to customize `HTTPServer` initialization, including setting a `startup_timeout`. This ensures the server is ready to serve requests before tests proceed. The server is started, yielded, and then stopped after the tests. ```python from collections.abc import Generator import pytest import requests from pytest_httpserver import HTTPServer @pytest.fixture(scope="session") def make_httpserver() -> Generator[HTTPServer, None, None]: server = HTTPServer(startup_timeout=10) # wait for 10 seconds for the server to be ready server.start() yield server server.clear() if server.is_running(): server.stop() ``` -------------------------------- ### Expect GET Request with Dictionary Query String Source: https://github.com/csernazs/pytest-httpserver/blob/master/doc/tutorial.md Use a dictionary for query parameters to ignore order when matching requests. ```python httpserver.expect_request( "/foobar", query_string={"user": "user1", "group": "group1"}, method="GET" ) ``` -------------------------------- ### Test Simplified Request/Response Handling Source: https://github.com/csernazs/pytest-httpserver/blob/master/doc/howto.md Demonstrates a simplified test case for handling client requests and server responses. It starts a client thread, asserts an incoming request on the server, and responds to it, then verifies the client received the correct response. ```python def test_simplified(httpserver: BlockingHTTPServer): def client(response_queue: Queue): response = requests.get(httpserver.url_for("/foobar"), timeout=10) response_queue.put(response) # start the client, server is not yet configured # it will block until we add a request handler to the server # (see the timeout parameter of the http server) response_queue: Queue[requests.models.Response] = Queue(maxsize=1) thread = threading.Thread(target=client, args=(response_queue,)) thread.start() try: # check that the request is for /foobar and it is a GET method # if this does not match, it will raise AssertionError and test will fail client_connection = httpserver.assert_request(uri="/foobar", method="GET") # with the received client_connection, we now need to send back the response # this makes the request.get() call in client() to return client_connection.respond_with_json({"foo": "bar"}) finally: # wait for the client thread to complete thread.join(timeout=1) assert not thread.is_alive() # check if join() has not timed out # check the response the client received response = response_queue.get(timeout=1) assert response.status_code == 200 assert response.json() == {"foo": "bar"} ``` -------------------------------- ### HTTPServer Error Output Example Source: https://github.com/csernazs/pytest-httpserver/blob/master/doc/tutorial.md This is an example of the AssertionError message generated by `httpserver.check()` when a request does not match any configured handlers, showing details about the unmatched request and the available matchers. ```text > raise AssertionError(assertion) E AssertionError: No handler found for request with data b''.Ordered matchers: E > E > E E Oneshot matchers: E none E E Persistent matchers: E none ``` -------------------------------- ### Expect GET Request with Query String Source: https://github.com/csernazs/pytest-httpserver/blob/master/doc/tutorial.md Specify a query string parameter for an expected GET request. ```python httpserver.expect_request("/foobar", query_string="user=user1", method="GET") ``` -------------------------------- ### Handle Simple GET Request with pytest Source: https://github.com/csernazs/pytest-httpserver/blob/master/README.md Use the `httpserver` fixture to set up an expectation for a GET request to '/foobar' and respond with JSON. This is useful for testing client behavior when a specific endpoint returns a predictable JSON response. ```python def test_my_client( httpserver, ): httpserver.expect_request("/foobar").respond_with_json({"foo": "bar"}) assert requests.get(httpserver.url_for("/foobar")).json() == {"foo": "bar"} ``` -------------------------------- ### Standalone HTTP Server with Context Manager Source: https://github.com/csernazs/pytest-httpserver/blob/master/README.md Use the `HTTPServer` class with a `with` statement for standalone testing without pytest. This ensures the server is properly started and stopped, allowing you to define request expectations and make requests within the context. ```python with HTTPServer() as httpserver: httpserver.expect_request("/foobar").respond_with_json({"foo": "bar"}) print(requests.get(httpserver.url_for("/foobar")).json()) ``` -------------------------------- ### Expect GET Request on /foobar Source: https://github.com/csernazs/pytest-httpserver/blob/master/doc/tutorial.md Limit the expected request method to GET for a specific path. ```python httpserver.expect_request("/foobar", method="GET") ``` -------------------------------- ### Send HTTP Request and Assert Response Source: https://github.com/csernazs/pytest-httpserver/blob/master/doc/tutorial.md Send an HTTP GET request to the mocked server URL and assert that the JSON response matches the expected data. Use `httpserver.url_for()` to construct the correct URL. ```python assert requests.get(httpserver.url_for("/foobar")).json() == {"foo": "bar"} ``` -------------------------------- ### Expect Request with Regex URI Source: https://github.com/csernazs/pytest-httpserver/blob/master/doc/tutorial.md Use a compiled regular expression to match URIs starting with a pattern. ```python httpserver.expect_request( re.compile("^/foo"), query_string={"user": "user1", "group": "group1"}, method="GET" ) ``` -------------------------------- ### Match URI using a regular expression Source: https://github.com/csernazs/pytest-httpserver/blob/master/doc/howto.md Use `re.compile()` to create a regular expression object for matching URIs. This allows for pattern-based matching, such as matching URIs that start with a specific prefix. ```python import re import requests def test_httpserver_with_regexp(httpserver): httpserver.expect_request(re.compile("^/foo"), method="GET") requests.get(httpserver.url_for("/foobar")) ``` -------------------------------- ### Test JSON Client with Mocked Response Source: https://github.com/csernazs/pytest-httpserver/blob/master/doc/index.md This snippet demonstrates how to test an HTTP client by mocking a JSON response from the server. It uses `requests` to make a GET request to a URL provided by `httpserver` and asserts that the JSON response matches the expected output. ```python import requests def test_json_client(httpserver: HTTPServer): httpserver.expect_request("/foobar").respond_with_json({"foo": "bar"}) assert requests.get(httpserver.url_for("/foobar")).json() == {"foo": "bar"} ``` -------------------------------- ### Emulate Connection Refused Error Source: https://github.com/csernazs/pytest-httpserver/blob/master/doc/howto.md To simulate a 'Connection refused' error, attempt to connect to a port where no service is actively listening. This example uses `pytest.raises` to assert that a `requests.exceptions.ConnectionError` occurs. ```python import pytest import requests def test_connection_refused(): # assumes that there's no server listening at localhost:1234 with pytest.raises(requests.exceptions.ConnectionError): requests.get("http://localhost:1234") ``` -------------------------------- ### Configure HTTPS Server SSL Context Source: https://github.com/csernazs/pytest-httpserver/blob/master/doc/howto.md Sets up the SSL context for the HTTPS server using a Certificate Authority (CA) provided by trustme. This is necessary for running tests over HTTPS. ```python @pytest.fixture(scope="session") def ca(): return trustme.CA() @pytest.fixture(scope="session") def httpserver_ssl_context(ca): context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) localhost_cert = ca.issue_cert("localhost") localhost_cert.configure_cert(context) return context ``` -------------------------------- ### Configure Request Expectation Source: https://github.com/csernazs/pytest-httpserver/blob/master/doc/tutorial.md Define the specific HTTP request that the server should expect. This is the first step in setting up a mock response. ```python httpserver.expect_request("/foobar") ``` -------------------------------- ### Configure HTTP Client SSL Context Source: https://github.com/csernazs/pytest-httpserver/blob/master/doc/howto.md Creates an SSL context for the HTTP client, trusting the CA generated by trustme. This allows the client to securely connect to the HTTPS server. ```python @pytest.fixture(scope="session") def httpclient_ssl_context(ca): with ca.cert_pem.tempfile() as ca_temp_path: return ssl.create_default_context(cafile=ca_temp_path) ``` -------------------------------- ### Run HTTPServer in Blocking Mode Source: https://github.com/csernazs/pytest-httpserver/blob/master/doc/howto.md Demonstrates how to run the HTTPServer in blocking mode, where the client code executes in a background thread and server events are synchronized to the main thread. This mode is experimental and requires manual assertion checking. ```python import threading from queue import Queue import pytest import requests from pytest_httpserver import BlockingHTTPServer ``` -------------------------------- ### Basic Test with HTTPServer Source: https://github.com/csernazs/pytest-httpserver/blob/master/doc/howto.md A basic test case demonstrating how to use the `httpserver` fixture to define a request handler and send a request to the server. Asserts the response status code and JSON body. ```python def test_example(httpserver: HTTPServer): # the server is ready at this point, you can add request handlers and start sending requests httpserver.expect_request("/foobar").respond_with_json({"foo": "bar"}) response = requests.get(httpserver.url_for("/foobar")) assert response.status_code == 200 assert response.json() == {"foo": "bar"} ``` -------------------------------- ### Emulate Timeout with a Sleeping Handler Source: https://github.com/csernazs/pytest-httpserver/blob/master/doc/howto.md Simulate a request timeout by registering a handler that sleeps for a duration longer than the client's specified timeout. This example uses `time.sleep` and asserts that a `requests.exceptions.ReadTimeout` is raised. ```python import time from pytest_httpserver import HTTPServer import pytest import requests def sleeping(request): time.sleep(2) # this should be greater than the client's timeout parameter def test_timeout(httpserver: HTTPServer): httpserver.expect_request("/baz").respond_with_handler(sleeping) with pytest.raises(requests.exceptions.ReadTimeout): assert requests.get(httpserver.url_for("/baz"), timeout=1) ``` -------------------------------- ### Respond with Static Data Source: https://github.com/csernazs/pytest-httpserver/blob/master/doc/tutorial.md Use `respond_with_data` to return a static response. This is suitable for simple, unchanging responses. ```python respond_with_data("Hello world!") ``` -------------------------------- ### WaitingSettings Source: https://github.com/csernazs/pytest-httpserver/blob/master/doc/api.md Configuration for waiting on server events. ```APIDOC ## WaitingSettings ### Description Defines settings related to how long to wait for certain server conditions or responses. ### Usage Configures timeouts and polling intervals for asynchronous operations or specific request handling scenarios. ``` -------------------------------- ### Match query parameters using a dictionary Source: https://github.com/csernazs/pytest-httpserver/blob/master/doc/howto.md For flexible matching where parameter order doesn't matter, provide a dictionary to the `query_string` parameter. The library parses the query string and compares it with the provided dictionary. ```python import requests def test_query_params(httpserver): httpserver.expect_request("/foo", query_string={"user": "user1", "group": "group1"}).respond_with_data("OK") assert requests.get(httpserver.url_for("/foo?user=user1&group=group1")).status_code == 200 assert requests.get(httpserver.url_for("/foo?group=group1&user=user1")).status_code == 200 ``` -------------------------------- ### Chain bake() calls for layered defaults Source: https://github.com/csernazs/pytest-httpserver/blob/master/doc/howto.md You can chain `bake()` calls to layer multiple sets of defaults. This allows for more granular configuration of baked server proxies. ```python json_post = httpserver.bake(method="POST").bake( headers={"Content-Type": "application/json"} ) ``` -------------------------------- ### Define Request Expectation with Query Parameters Source: https://github.com/csernazs/pytest-httpserver/blob/master/doc/background.md Use this to define a simple request expectation with specific query parameters. The response will be a static data payload. ```python def test_query_params(httpserver): httpserver.expect_request("/foo", query_string={"user": "user1"}).respond_with_data("OK") ``` -------------------------------- ### Querying Request Logs with pytest-httpserver Source: https://github.com/csernazs/pytest-httpserver/blob/master/doc/howto.md Demonstrates how to use methods like get_matching_requests_count, assert_request_made, and iter_matching_requests to inspect server logs. Requires importing HTTPServer and RequestMatcher. ```python import requests from pytest_httpserver import HTTPServer from pytest_httpserver import RequestMatcher def test_log_querying_example(httpserver: HTTPServer): # set up the handler for the request httpserver.expect_request("/foo").respond_with_data("OK") # make a request matching the handler assert requests.get(httpserver.url_for("/foo")).text == "OK", "Response should be 'OK'" # make another request non-matching and handler assert ( requests.get(httpserver.url_for("/no_match")).status_code == 500 ), "Response code should be 500 for non-matched requests" # you can query the log directly # log will contain all request-response pair, including non-matching # requests and their response as well assert len(httpserver.log) == 2, "2 request-response pairs should be in the log" # there are the following methods to query the log # # each one uses the matcher we created for the handler in the very beginning # of this test, RequestMatcher accepts the same parameters what you were # specifying to the `expect_request` (and similar) methods. # 1. get counts # (returns 0 for non-matches) httpserver.get_matching_requests_count( RequestMatcher("/foo") ) == 1, "There should be one request matching the the /foo request" # 2. assert for matching request counts # by default it asserts for exactly 1 matches # it is roughly the same as: # ``` # assert httpserver.get_matching_requests_count(...) == 1 # ``` # assertion text will be a fully-detailed explanation about the error, including # the similar handlers (which might have been inproperly configured) httpserver.assert_request_made(RequestMatcher("/foo")) # you can also specify the counts # if you want, you can specify 0 to check for non-matching requests # there should have been 0 requests for /bar httpserver.assert_request_made(RequestMatcher("/bar"), count=0) # 3. iterate over the matching request-response pairs # this provides you greater flexibility for request, response in httpserver.iter_matching_requests(RequestMatcher("/foo")): assert request.url == httpserver.url_for("/foo") assert response.get_data() == b"OK" ``` -------------------------------- ### Test HTTPS Server with httpx Source: https://github.com/csernazs/pytest-httpserver/blob/master/doc/howto.md Tests the HTTPS server using the httpx client. The SSL context is directly passed to the httpx.get function for verification. ```python def test_httpx(httpserver, httpclient_ssl_context): import httpx httpserver.expect_request("/").respond_with_data("hello world!") result = httpx.get(httpserver.url_for("/"), verify=httpclient_ssl_context) assert result.text == "hello world!" ``` -------------------------------- ### Test HTTPS Server with aiohttp Source: https://github.com/csernazs/pytest-httpserver/blob/master/doc/howto.md Tests the HTTPS server using the aiohttp client. Requires an SSL context for the client to establish a secure connection. ```python @pytest.mark.asyncio async def test_aiohttp(httpserver, httpclient_ssl_context): import aiohttp httpserver.expect_request("/").respond_with_data("hello world!") connector = aiohttp.TCPConnector(ssl=httpclient_ssl_context) async with aiohttp.ClientSession(connector=connector) as session: async with session.get(httpserver.url_for("/")) as result: assert (await result.text()) == "hello world!" ``` -------------------------------- ### Define Request Expectation with Query Parameters using Variable Source: https://github.com/csernazs/pytest-httpserver/blob/master/doc/background.md This demonstrates defining a request expectation with query parameters stored in a variable for better readability. The response is a static data payload. ```python def test_query_params(httpserver): expected_query = {"user": "user1"} httpserver.expect_request("/foo", query_string=expected_query).respond_with_data("OK") ``` -------------------------------- ### Respond with Dynamic Content using a Handler Source: https://github.com/csernazs/pytest-httpserver/blob/master/doc/tutorial.md Use `respond_with_handler` to return dynamic content by providing a callable function. This function receives the request object and should return a `Response` object. ```python def my_handler(request): # here, examine the request object return Response("Hello world!") respond_with_handler(my_handler) ``` -------------------------------- ### Test HTTPS Server with requests Source: https://github.com/csernazs/pytest-httpserver/blob/master/doc/howto.md Tests the HTTPS server using the requests library. The client's SSL verification is configured using a temporary file containing the CA's certificate. ```python def test_requests(httpserver, ca): import requests httpserver.expect_request("/").respond_with_data("hello world!") with ca.cert_pem.tempfile() as ca_temp_path: result = requests.get(httpserver.url_for("/"), verify=ca_temp_path) assert result.text == "hello world!" ``` -------------------------------- ### Basic Debugging with check() Source: https://github.com/csernazs/pytest-httpserver/blob/master/doc/tutorial.md Use `httpserver.check()` after requests to fail the test immediately if an unexpected request is made. This helps pinpoint issues earlier in the test execution. ```python import requests def test_json_client(httpserver: HTTPServer): httpserver.expect_request("/foobar").respond_with_json({"foo": "bar"}) requests.get(httpserver.url_for("/foo")) requests.get(httpserver.url_for("/bar")) requests.get(httpserver.url_for("/foobar")) httpserver.check() ``` -------------------------------- ### Respond with Werkzeug Response Object Source: https://github.com/csernazs/pytest-httpserver/blob/master/doc/tutorial.md Create and return a custom Response object from the werkzeug library for advanced customization. ```python respond_with_response(Response("Hello world!")) ``` -------------------------------- ### RequestMatcherKwargs Source: https://github.com/csernazs/pytest-httpserver/blob/master/doc/api.md Keyword arguments used for matching incoming requests. ```APIDOC ## RequestMatcherKwargs ### Description Represents a set of criteria used to match an incoming HTTP request, such as headers, query parameters, or request body. ### Usage Passed to `HTTPServer.request()` to define detailed matching rules. ``` -------------------------------- ### Wait for Handlers in Multi-threaded Clients Source: https://github.com/csernazs/pytest-httpserver/blob/master/doc/howto.md Use the `httpserver.wait()` context manager to synchronize server state with the main thread when clients run in separate threads. It helps ensure all handlers are served or errors are caught before proceeding. ```python import requests from pytest_httpserver import HTTPServer def test_wait_success(httpserver: HTTPServer): waiting_timeout = 0.1 with httpserver.wait(stop_on_nohandler=False, timeout=waiting_timeout) as waiting: requests.get(httpserver.url_for("/foobar")) httpserver.expect_oneshot_request("/foobar").respond_with_data("OK foobar") requests.get(httpserver.url_for("/foobar")) assert waiting.result httpserver.expect_oneshot_request("/foobar").respond_with_data("OK foobar") httpserver.expect_oneshot_request("/foobaz").respond_with_data("OK foobaz") with httpserver.wait(timeout=waiting_timeout) as waiting: requests.get(httpserver.url_for("/foobar")) requests.get(httpserver.url_for("/foobaz")) assert waiting.result ``` -------------------------------- ### HTTPServer Source: https://github.com/csernazs/pytest-httpserver/blob/master/doc/api.md The main class for creating and managing a mock HTTP server within pytest tests. ```APIDOC ## HTTPServer ### Description Provides an interface to start, stop, and configure a mock HTTP server for testing purposes. ### Usage Instantiate and use within your pytest fixtures or test functions. ### Methods - `start()`: Starts the HTTP server. - `stop()`: Stops the HTTP server. - `request()`: Configures a request handler for incoming HTTP requests. - `url_for(path)`: Generates a URL for a given path on the mock server. ``` -------------------------------- ### Match query parameters using a string Source: https://github.com/csernazs/pytest-httpserver/blob/master/doc/howto.md Specify query parameters using the `query_string` parameter in `expect_request`. The string should not include the leading question mark. ```python def test_query_params(httpserver): httpserver.expect_request("/foo", query_string="user=bar") ``` -------------------------------- ### Bake common defaults for multiple expectations Source: https://github.com/csernazs/pytest-httpserver/blob/master/doc/howto.md Use `httpserver.bake()` to set common defaults for method and headers. This reduces repetition when defining multiple `expect_request` calls with similar configurations. ```python import requests from pytest_httpserver import HTTPServer def test_bake_json_api(httpserver: HTTPServer) -> None: # bake common defaults so you don't repeat them for every expect_request json_api = httpserver.bake(method="POST", headers={"Content-Type": "application/json"}) json_api.expect_request("/users").respond_with_json({"id": 1, "name": "Alice"}, status=201) json_api.expect_request("/items").respond_with_json({"id": 42, "name": "Widget"}, status=201) resp = requests.post( httpserver.url_for("/users"), json={"name": "Alice"}, ) assert resp.status_code == 201 assert resp.json() == {"id": 1, "name": "Alice"} resp = requests.post( httpserver.url_for("/items"), json={"name": "Widget"}, ) assert resp.status_code == 201 assert resp.json() == {"id": 42, "name": "Widget"} ``` -------------------------------- ### RequestHandler Source: https://github.com/csernazs/pytest-httpserver/blob/master/doc/api.md Defines how the server should respond to specific incoming requests. ```APIDOC ## RequestHandler ### Description Used to specify the response for a matched request, including status code, headers, and body. ### Usage Typically returned by `HTTPServer.request()` and configured with response details. ### Parameters - `method` (str): The HTTP method to match (e.g., 'GET', 'POST'). - `uri` (str): The URI path to match. - `response_code` (int): The HTTP status code to return. - `response_body` (str): The content of the response body. - `response_headers` (dict): A dictionary of response headers. ``` -------------------------------- ### Override httpserver_listen_address Fixture Source: https://github.com/csernazs/pytest-httpserver/blob/master/doc/howto.md Override the `httpserver_listen_address` fixture to specify the host and port for the test server. This must be done before the `httpserver` fixture is used. ```python import pytest @pytest.fixture(scope="session") def httpserver_listen_address(): return ("127.0.0.1", 8000) ``` -------------------------------- ### Match URI using a custom URIPattern object Source: https://github.com/csernazs/pytest-httpserver/blob/master/doc/howto.md Extend URI matching functionality by subclassing `URIPattern` and implementing the `match()` method. This allows for custom matching logic, such as prefix matching. ```python from pytest_httpserver import HTTPServer from pytest_httpserver import URIPattern class PrefixMatch(URIPattern): def __init__(self, prefix: str): self.prefix = prefix def match(self, uri): return uri.startswith(self.prefix) def test_uripattern_object(httpserver: HTTPServer): httpserver.expect_request(PrefixMatch("/foo")).respond_with_json({"foo": "bar"}) ``` -------------------------------- ### Test Normal Connection to HTTPServer Source: https://github.com/csernazs/pytest-httpserver/blob/master/doc/howto.md This test demonstrates a successful connection to the httpserver running on a specified port. It expects a request and asserts the response text. ```python import pytest import requests # setting a fixed port for httpserver @pytest.fixture(scope="session") def httpserver_listen_address(): return ("127.0.0.1", 8000) # this test will pass def test_normal_connection(httpserver): httpserver.expect_request("/foo").respond_with_data("foo") assert requests.get("http://localhost:8000/foo").text == "foo" ``` -------------------------------- ### Create a Custom Threaded HTTPServer Fixture Source: https://github.com/csernazs/pytest-httpserver/blob/master/doc/howto.md Define a custom pytest fixture to create a threaded HTTPServer instance. This allows for concurrent request handling and can be used alongside the default fixture. ```python import pytest from typing import Iterable from pytest_httpserver import HTTPServer @pytest.fixture() def threaded() -> Iterable[HTTPServer]: server = HTTPServer(threaded=True) server.start() yield server server.clear() if server.is_running(): server.stop() def test_threaded(threaded: HTTPServer): ... ``` -------------------------------- ### Respond with Custom Status and Data Source: https://github.com/csernazs/pytest-httpserver/blob/master/doc/tutorial.md Send a response with a specific status code (e.g., 404) and plain text data. ```python respond_with_data("Not found", status=404, content_type="text/plain") ``` -------------------------------- ### Check Ordered Requests with HTTPServer Source: https://github.com/csernazs/pytest-httpserver/blob/master/doc/tutorial.md Use `httpserver.check()` to raise an AssertionError if requests do not match expected ordered patterns or if there are unhandled requests. This is useful for ensuring strict request sequencing. ```python def test_ordered_ok(httpserver: HTTPServer): httpserver.expect_ordered_request("/foobar").respond_with_data("OK foobar") httpserver.expect_ordered_request("/foobaz").respond_with_data("OK foobaz") requests.get(httpserver.url_for("/foobaz")) requests.get(httpserver.url_for("/foobar")) # gets 500 httpserver.check() # this will raise AssertionError and make the test failing ``` -------------------------------- ### RequestMatcher Source: https://github.com/csernazs/pytest-httpserver/blob/master/doc/api.md An object that encapsulates the logic for matching requests. ```APIDOC ## RequestMatcher ### Description An internal representation of request matching criteria, often built from `RequestMatcherKwargs`. ### Usage Used internally by `HTTPServer` to find the appropriate handler for a request. ``` -------------------------------- ### Ordered Requests Failing on Incorrect Order Source: https://github.com/csernazs/pytest-httpserver/blob/master/doc/tutorial.md Demonstrates how an incorrect request order will fail when checking status codes. The server runs in a separate thread, so assertion errors must be checked explicitly. ```python def test_ordered(httpserver: HTTPServer): httpserver.expect_ordered_request("/foobar").respond_with_data("OK foobar") httpserver.expect_ordered_request("/foobaz").respond_with_data("OK foobaz") assert requests.get(httpserver.url_for("/foobaz")).status_code == 200 assert requests.get(httpserver.url_for("/foobar")).status_code == 200 # <- fail! ``` -------------------------------- ### Implement a Custom Request Matcher Source: https://github.com/csernazs/pytest-httpserver/blob/master/doc/howto.md Extend `RequestMatcher` to create custom logic for matching incoming requests. The `match` method should return `True` if the request matches, and `False` otherwise. Ensure to call `super().match(request)` first. ```python import requests from werkzeug import Request from pytest_httpserver import HTTPServer from pytest_httpserver import RequestMatcher class MyMatcher(RequestMatcher): def match(self, request: Request) -> bool: match = super().match(request) if not match: # existing parameters didn't match -> return with False return match # match the json's "value" key: if it is an integer and it is an even # number, it returns True json = request.json if isinstance(json, dict) and isinstance(json.get("value"), int): return json["value"] % 2 == 0 return False def test_custom_request_matcher(httpserver: HTTPServer): httpserver.expect(MyMatcher("/foo")).respond_with_data("OK") # with even number it matches the request resp = requests.post(httpserver.url_for("/foo"), json={"value": 42}) resp.raise_for_status() assert resp.text == "OK" resp = requests.post(httpserver.url_for("/foo"), json={"value": 198}) resp.raise_for_status() assert resp.text == "OK" # with an odd number, it does not match the request resp = requests.post(httpserver.url_for("/foo"), json={"value": 43}) assert resp.status_code == 500 ``` -------------------------------- ### Handle POST Request with JSON Body using pytest Source: https://github.com/csernazs/pytest-httpserver/blob/master/README.md Configure the `httpserver` fixture to expect a POST request to '/foobar' with a specific JSON body and respond with JSON. This is ideal for testing clients that send JSON data in POST requests. ```python def test_json_request( httpserver, ): httpserver.expect_request( "/foobar", method="POST", json={"id": 12, "name": "foo"} ).respond_with_json({"foo": "bar"}) assert requests.post( httpserver.url_for("/foobar"), json={"id": 12, "name": "foo"} ).json() == {"foo": "bar"} ``` -------------------------------- ### HeaderValueMatcher Source: https://github.com/csernazs/pytest-httpserver/blob/master/doc/api.md Matches header values. ```APIDOC ## HeaderValueMatcher ### Description Provides a mechanism to match specific values for HTTP headers, allowing for flexible header inspection. ### Usage Used within request matching to assert the presence and value of specific headers. ``` -------------------------------- ### Test Connection Refused When Server is Running Source: https://github.com/csernazs/pytest-httpserver/blob/master/doc/howto.md This test is designed to fail by attempting to connect to a port where the httpserver is expected to be running, but with handlers removed. It will result in a 500 status code rather than a 'Connection refused' error. ```python import pytest import requests # setting a fixed port for httpserver @pytest.fixture(scope="session") def httpserver_listen_address(): return ("127.0.0.1", 8000) # this tess will FAIL, as httpserver started in test_normal_connection is # still running def test_connection_refused(): with pytest.raises(requests.exceptions.ConnectionError): # this won't get Connection refused error as the server is still # running. # it will get HTTP status 500 as the handlers registered in # test_normal_connection have been removed requests.get("http://localhost:8000/foo") ``` -------------------------------- ### HTTPServerError Source: https://github.com/csernazs/pytest-httpserver/blob/master/doc/api.md Base exception for server errors. ```APIDOC ## HTTPServerError ### Description The base exception class for all errors raised by the `pytest-httpserver` library. ### Usage Can be caught to handle specific server-related issues. ``` -------------------------------- ### Global HTTPServer Check with Fixture Override Source: https://github.com/csernazs/pytest-httpserver/blob/master/doc/tutorial.md Override the `httpserver` fixture to automatically call `httpserver.check()` after each test. This ensures that all tests using the fixture will have their request matching verified, failing the test if any discrepancies are found. ```python from collections.abc import Iterable from pytest_httpserver import HTTPServer import requests import pytest @pytest.fixture def httpserver(httpserver: HTTPServer) -> Iterable[HTTPServer]: yield httpserver httpserver.check() # this will raise AssertionError and make the test failing def test_client(httpserver: HTTPServer): httpserver.expect_request("/foo").respond_with_data("foo") httpserver.expect_request("/bar").respond_with_data("bar") resp = requests.get(httpserver.url_for("/foobar")) # gets 500 resp.raise_for_status() # raises error ``` -------------------------------- ### Implement and Use a Custom Post-Hook Source: https://github.com/csernazs/pytest-httpserver/blob/master/doc/howto.md Create a custom callable function to act as a post-hook for request handlers. This hook can modify the response, such as adding custom headers, before it's sent to the client. ```python import requests from werkzeug import Request from werkzeug import Response from pytest_httpserver import HTTPServer def my_hook(_request: Request, response: Response) -> Response: # add a new header value to the response response.headers["X-Example"] = "Example" return response def test_custom_hook(httpserver: HTTPServer): httpserver.expect_request("/foo").with_post_hook(my_hook).respond_with_data(b"OK") assert requests.get(httpserver.url_for("/foo")).headers["X-Example"] == "Example" ``` -------------------------------- ### Explicitly Stop HTTPServer for Connection Refused Test Source: https://github.com/csernazs/pytest-httpserver/blob/master/doc/howto.md To correctly test a 'Connection refused' scenario after a previous test, explicitly stop the httpserver using `httpserver.stop()`. This ensures the port is free for the connection error to be raised. ```python def test_connection_refused(httpserver): httpserver.stop() # stop the server explicitly with pytest.raises(requests.exceptions.ConnectionError): requests.get("http://localhost:8000/foo") ``` -------------------------------- ### Oneshot Requests Failing on Second Call Source: https://github.com/csernazs/pytest-httpserver/blob/master/doc/tutorial.md Demonstrates how a second request to a oneshot handler will fail when checking status codes. The server runs in a separate thread, so assertion errors must be checked explicitly. ```python def test_oneshot(httpserver: HTTPServer): httpserver.expect_oneshot_request("/foobar").respond_with_data("OK") assert requests.get(httpserver.url_for("/foobar")).status_code == 200 assert requests.get(httpserver.url_for("/foobar")).status_code == 200 # fail! ``` -------------------------------- ### Incremental Debugging with Multiple check() Calls Source: https://github.com/csernazs/pytest-httpserver/blob/master/doc/tutorial.md Place `httpserver.check()` calls after each request to isolate failures to the specific request that caused the issue. This provides more granular debugging information. ```python import requests def test_json_client(httpserver: HTTPServer): httpserver.expect_request("/foobar").respond_with_json({"foo": "bar"}) requests.get(httpserver.url_for("/foo")) httpserver.check() requests.get(httpserver.url_for("/bar")) httpserver.check() requests.get(httpserver.url_for("/foobar")) httpserver.check() ``` -------------------------------- ### Respond with Plain Text Data Source: https://github.com/csernazs/pytest-httpserver/blob/master/doc/tutorial.md Send a plain text response with a specified content type. ```python respond_with_data("Hello world!", content_type="text/plain") ``` -------------------------------- ### Configure JSON Response Source: https://github.com/csernazs/pytest-httpserver/blob/master/doc/tutorial.md Specify the JSON response to be sent back when a matching request is received. The library accepts any JSON-serializable Python object. ```python respond_with_json({"foo": "bar"}) ``` -------------------------------- ### BlockingHTTPServer Source: https://github.com/csernazs/pytest-httpserver/blob/master/doc/api.md An HTTP server that blocks until a response is ready. ```APIDOC ## BlockingHTTPServer ### Description A server implementation that ensures requests are handled sequentially and responses are blocked until fully prepared. ### Usage Useful for tests where the order of operations and response completeness are critical. ``` -------------------------------- ### BakedHTTPServer Source: https://github.com/csernazs/pytest-httpserver/blob/master/doc/api.md A specialized HTTP server that bakes responses. ```APIDOC ## BakedHTTPServer ### Description An extension of `HTTPServer` that allows for pre-baking responses, potentially improving performance for static responses. ### Usage Use when you need to serve static content efficiently. ``` -------------------------------- ### Override HTTPServer Fixture Source: https://github.com/csernazs/pytest-httpserver/blob/master/doc/howto.md This fixture overrides the default httpserver to include custom server start/stop logic and request checking. It ensures the server is properly managed during tests. ```python @pytest.fixture def httpserver(): server = BlockingHTTPServer(timeout=1) server.start() yield server if server.is_running(): server.stop() # this is to check if the client has made any request where no # `assert_request` was called on it from the test server.check() server.clear() ``` -------------------------------- ### Combined Test Failures with Verbose Output Source: https://github.com/csernazs/pytest-httpserver/blob/master/doc/tutorial.md When running tests with `-vv`, this output shows both an HTTPError from a client-side issue (like a 500 status) and an AssertionError from `httpserver.check()` due to unmatched requests, providing comprehensive debugging information. ```text FAILED example2.py::test_client - requests.exceptions.HTTPError: 500 Server Error: INTERNAL SERVER ERROR for url: http://localhost:37425/foobar ERROR example2.py::test_client - AssertionError: No handler found for request with data b''. Ordered matchers: none Oneshot matchers: none Persistent matchers: > > ``` -------------------------------- ### Avoid matching query parameters in URI Source: https://github.com/csernazs/pytest-httpserver/blob/master/doc/howto.md Do not include query parameters directly in the URI string when defining expectations. Use the `query_string` parameter instead. ```python def test_query_params(httpserver): httpserver.expect_request("/foo?user=bar") # never do this ``` -------------------------------- ### Define a Custom Request Handler Source: https://github.com/csernazs/pytest-httpserver/blob/master/doc/howto.md Use `respond_with_handler` to pass a function that generates dynamic responses based on the request. The handler receives a `Request` object and must return a `Response` object. ```python from random import randint from werkzeug import Request from werkzeug import Response from pytest_httpserver import HTTPServer def test_expected_request_handler(httpserver: HTTPServer): def handler(request: Request): return Response(str(randint(1, 10))) httpserver.expect_request("/foobar").respond_with_handler(handler) ``` -------------------------------- ### Expect Oneshot Requests Source: https://github.com/csernazs/pytest-httpserver/blob/master/doc/tutorial.md Use `expect_oneshot_request` to define a handler that will only respond once. Subsequent requests to the same URL will result in an error (e.g., HTTP 500). ```python def test_oneshot(httpserver: HTTPServer): httpserver.expect_oneshot_request("/foobar").respond_with_data("OK") requests.get(httpserver.url_for("/foobar")) requests.get(httpserver.url_for("/foobar")) # this will get http status 500 ```