# Backend Testing Tools and Libraries in Shadowbroker: A Complete Guide

> Discover backend testing tools and libraries in Shadowbroker. Learn how pytest, pytest-asyncio, and httpx create an async testing environment for efficient FastAPI backend verification.

- Repository: [Shadowbroker/Shadowbroker](https://github.com/BigBodyCobain/Shadowbroker)
- Tags: how-to-guide
- Published: 2026-05-07

---

**Shadowbroker uses pytest, pytest-asyncio, and httpx to create an asynchronous testing environment for its FastAPI backend, enabling in-process HTTP testing without launching real servers.**

The Shadowbroker repository implements a Python FastAPI service that relies on a comprehensive testing stack defined in its project metadata. Understanding the backend testing tools and libraries in Shadowbroker provides insight into how the codebase achieves fast, deterministic validation of API endpoints while maintaining full integration coverage. The configuration found in [`backend/pyproject.toml`](https://github.com/BigBodyCobain/Shadowbroker/blob/main/backend/pyproject.toml) and the test suite within `backend/tests/` demonstrate modern patterns for async Python web application testing.

## Core Testing Libraries

### pytest and pytest-asyncio

**pytest** serves as the primary test runner and assertion framework, declared as a development dependency in [`backend/pyproject.toml`](https://github.com/BigBodyCobain/Shadowbroker/blob/main/backend/pyproject.toml). The **pytest-asyncio** plugin extends this capability to support asynchronous test functions, enabling `async def` fixtures and test cases throughout the suite. This combination allows the test runner to properly handle the async/await patterns inherent to FastAPI applications.

### httpx with ASGITransport

**httpx** provides the HTTP client for integration tests, utilized with `ASGITransport` to create an in-process bridge to the FastAPI application. The `client` fixture in [`backend/tests/conftest.py`](https://github.com/BigBodyCobain/Shadowbroker/blob/main/backend/tests/conftest.py) constructs an `httpx.AsyncClient` using `ASGITransport(app=app)`, allowing tests to invoke endpoints like `client.get("/api/health")` without spinning up a real network stack or external server.

### FastAPI and Pydantic

While **FastAPI** is the web framework under test, **Pydantic** handles request and response schema validation. The test suite verifies that invalid inputs automatically trigger `422` validation errors, as demonstrated in [`test_api_smoke.py`](https://github.com/BigBodyCobain/Shadowbroker/blob/main/test_api_smoke.py)’s `TestQueryValidation` class.

### unittest.mock for Service Isolation

The standard library's **unittest.mock** patches background services to prevent non-deterministic side effects. Fixtures in [`conftest.py`](https://github.com/BigBodyCobain/Shadowbroker/blob/main/conftest.py) suppress schedulers and streamers (such as `services.data_fetcher.start_scheduler` and `services.ais_stream.start_ais_stream`) to maintain a deterministic test environment.

## Test Configuration and Structure

### Dependency Management

All testing dependencies are centralized in [`backend/pyproject.toml`](https://github.com/BigBodyCobain/Shadowbroker/blob/main/backend/pyproject.toml), cleanly separating runtime requirements (`httpx`, `fastapi`, `pydantic`) from development tools (`pytest`, `pytest-asyncio`, `ruff`, `black`). This declarative approach ensures consistent environments across development and CI/CD pipelines.

### pytest.ini Discovery Rules

The [`backend/pytest.ini`](https://github.com/BigBodyCobain/Shadowbroker/blob/main/backend/pytest.ini) file configures test discovery patterns, ensuring pytest locates all test modules within the `backend/tests/` directory and applies the appropriate async test handling.

### Global Fixtures in conftest.py

The [`backend/tests/conftest.py`](https://github.com/BigBodyCobain/Shadowbroker/blob/main/backend/tests/conftest.py) file contains global fixtures that instantiate the HTTP client and suppress background tasks. The `client` fixture wraps `httpx.AsyncClient` with `ASGITransport` over the FastAPI app instance imported from [`backend/main.py`](https://github.com/BigBodyCobain/Shadowbroker/blob/main/backend/main.py).

## Testing Patterns and Code Examples

### Creating an In-Process Test Client

The test suite implements a synchronous wrapper around httpx's async client to simplify test writing. This pattern in [`backend/tests/conftest.py`](https://github.com/BigBodyCobain/Shadowbroker/blob/main/backend/tests/conftest.py) handles the event loop management internally:

```python

# backend/tests/conftest.py

@pytest.fixture()
def client(_suppress_background_services):
    from httpx import ASGITransport, AsyncClient
    from main import app

    transport = ASGITransport(app=app)

    class SyncClient:
        def __init__(self):
            self._loop = asyncio.new_event_loop()
            self._transport = ASGITransport(app=app)

        def get(self, url, **kw):
            return self._loop.run_until_complete(self._get(url, **kw))

        async def _get(self, url, **kw):
            async with AsyncClient(transport=self._transport, base_url="http://test") as ac:
                return await ac.get(url, **kw)

        # post / put / delete follow the same pattern …

    return SyncClient()

```

### Endpoint Smoke Testing

Basic health checks verify that the FastAPI application responds correctly to HTTP requests:

```python

# backend/tests/test_api_smoke.py

class TestHealthEndpoint:
    def test_health_returns_200(self, client):
        r = client.get("/api/health")
        assert r.status_code == 200
        data = r.json()
        assert data["status"] == "ok"

```

### Validation Error Testing

The integration tests verify that Pydantic returns proper HTTP 422 responses for malformed requests:

```python

# backend/tests/test_api_smoke.py

class TestQueryValidation:
    def test_region_dossier_rejects_invalid_lat(self, client):
        r = client.get("/api/region-dossier?lat=999&lng=0")
        assert r.status_code == 422

```

### Mocking Background Services

Fixtures use context managers to patch services that should not execute during tests:

```python

# backend/tests/conftest.py

with (
    patch("services.data_fetcher.start_scheduler"),
    patch("services.ais_stream.start_ais_stream"),
    # …other patches…

):
    yield

```

## Summary

- **pytest** and **pytest-asyncio** provide the async-capable test runner and assertion framework for the Python backend.
- **httpx** with `ASGITransport` enables in-process HTTP testing against the FastAPI application without network overhead.
- **unittest.mock** isolates the test environment by suppressing background services like schedulers and data streams.
- Configuration files [`backend/pyproject.toml`](https://github.com/BigBodyCobain/Shadowbroker/blob/main/backend/pyproject.toml) and [`backend/pytest.ini`](https://github.com/BigBodyCobain/Shadowbroker/blob/main/backend/pytest.ini) centralize dependencies and discovery rules.
- The `client` fixture in [`backend/tests/conftest.py`](https://github.com/BigBodyCobain/Shadowbroker/blob/main/backend/tests/conftest.py) demonstrates the synchronous wrapper pattern for async HTTP clients.

## Frequently Asked Questions

### What is the primary test runner used in Shadowbroker?

**pytest** is the primary test runner, configured via [`backend/pyproject.toml`](https://github.com/BigBodyCobain/Shadowbroker/blob/main/backend/pyproject.toml) and [`backend/pytest.ini`](https://github.com/BigBodyCobain/Shadowbroker/blob/main/backend/pytest.ini). It discovers and executes all test modules in the `backend/tests/` directory, providing assertion methods and reporting capabilities for the FastAPI backend testing suite.

### How does Shadowbroker handle asynchronous testing?

The project uses **pytest-asyncio** as a development dependency to enable `async def` test functions and fixtures. This allows the test suite to properly await coroutines when testing the asynchronous FastAPI endpoints, particularly when using `httpx.AsyncClient` for HTTP requests.

### Why does Shadowbroker use httpx instead of the standard TestClient?

Shadowbroker uses **httpx** with `ASGITransport` rather than FastAPI's `TestClient` because it provides direct async support and greater flexibility for integration testing. The `client` fixture in [`conftest.py`](https://github.com/BigBodyCobain/Shadowbroker/blob/main/conftest.py) wraps `httpx.AsyncClient` to create an in-process bridge to the FastAPI app at `base_url="http://test"`, eliminating the need for a real server while maintaining full HTTP semantics.

### Where are the test dependencies configured in the repository?

All test dependencies are declared in [`backend/pyproject.toml`](https://github.com/BigBodyCobain/Shadowbroker/blob/main/backend/pyproject.toml) under the development dependencies section. This includes `pytest`, `pytest-asyncio`, `httpx`, and code quality tools like `ruff` and `black`. The test discovery patterns are further configured in [`backend/pytest.ini`](https://github.com/BigBodyCobain/Shadowbroker/blob/main/backend/pytest.ini).