# Backend Testing Infrastructure in Screenshot-to-Code: pytest and pytest-asyncio Setup

> Discover the backend testing infrastructure for Screenshot-to-Code. Learn how pytest and pytest-asyncio streamline unit and integration testing for FastAPI.

- Repository: [Abi Raja/screenshot-to-code](https://github.com/abi/screenshot-to-code)
- Tags: internals
- Published: 2026-03-02

---

**The Screenshot-to-Code backend uses pytest with automatic async support via pytest-asyncio, configured through [`backend/pytest.ini`](https://github.com/abi/screenshot-to-code/blob/main/backend/pytest.ini) and managed by Poetry, allowing developers to run unit and integration tests against FastAPI routes and agents.**

The Screenshot-to-Code repository provides a robust backend testing infrastructure built on pytest. Located in the `backend/` directory, this setup supports both synchronous and asynchronous test patterns essential for validating FastAPI endpoints, agent logic, and LLM integration code.

## Testing Infrastructure Components

The testing stack is defined in [`backend/pyproject.toml`](https://github.com/abi/screenshot-to-code/blob/main/backend/pyproject.toml) and configured via [`backend/pytest.ini`](https://github.com/abi/screenshot-to-code/blob/main/backend/pytest.ini). This infrastructure enables comprehensive validation of the Python backend without requiring external test runners.

### Core Test Dependencies

The following tools form the backbone of the testing infrastructure as declared in the project's Poetry configuration:

- **pytest**: Discovers and executes tests according to the patterns defined in [`backend/pytest.ini`](https://github.com/abi/screenshot-to-code/blob/main/backend/pytest.ini).
- **pytest-asyncio**: Enables `async def` test functions for testing asynchronous FastAPI endpoints and HTTP clients. Declared in the dev dependency group in [`backend/pyproject.toml`](https://github.com/abi/screenshot-to-code/blob/main/backend/pyproject.toml).
- **pyright**: Performs static type checking through Poetry to prevent type errors from reaching production.

### Key Configuration Files

Two files control the test behavior and discovery:

- **[`backend/pytest.ini`](https://github.com/abi/screenshot-to-code/blob/main/backend/pytest.ini)**: Sets `testpaths = tests`, defines `asyncio_mode = auto` for automatic async handling, and applies verbose output (`-v`) with short tracebacks (`--tb=short`).
- **[`backend/pyproject.toml`](https://github.com/abi/screenshot-to-code/blob/main/backend/pyproject.toml)**: Declares test dependencies including `pytest` and `pytest-asyncio` in the Poetry dev group, as recommended by the project's [`AGENTS.md`](https://github.com/abi/screenshot-to-code/blob/main/AGENTS.md).

## Running the Backend Test Suite

Execute the full test suite from within the Poetry-managed environment.

First, ensure development dependencies are installed:

```bash
cd backend && poetry install

```

Then run pytest:

```bash
cd backend && poetry run pytest

```

When executed, pytest reads the configuration from [`backend/pytest.ini`](https://github.com/abi/screenshot-to-code/blob/main/backend/pytest.ini), collects tests from the `tests/` directory matching the `test_*.py` pattern, and automatically handles async tests via the `asyncio_mode = auto` setting. The output displays verbose results with short tracebacks, showing passed or failed status for each collected item.

## Writing Tests for the Backend

New test files belong in `backend/tests/` and must follow the `test_*.py` naming convention to be discovered by pytest.

### Synchronous Tests

For standard FastAPI route testing, use the synchronous `TestClient`. This pattern validates HTTP endpoints without requiring async syntax:

```python

# backend/tests/test_example.py

import pytest
from fastapi.testclient import TestClient
from backend.main import app

client = TestClient(app)

def test_home_route():
    response = client.get("/")
    assert response.status_code == 200
    assert response.json() == {"message": "Welcome to Screenshot-to-Code!"}

```

### Asynchronous Tests

When testing async functions, LLM helpers, or using `httpx.AsyncClient`, declare tests with `async def`. The `asyncio_mode = auto` setting in [`backend/pytest.ini`](https://github.com/abi/screenshot-to-code/blob/main/backend/pytest.ini) eliminates the need for `@pytest.mark.asyncio` decorators:

```python

# backend/tests/test_async_status.py

import pytest
from httpx import AsyncClient
from backend.main import app

async def test_status_endpoint():
    async with AsyncClient(app=app, base_url="http://test") as client:
         resp = await client.get("/status")
    assert resp.status_code == 200
    data = resp.json()
    assert data["state"] in {"idle", "running"}

```

The test `test_broadcast` in [`backend/tests/test_status_broadcast.py`](https://github.com/abi/screenshot-to-code/blob/main/backend/tests/test_status_broadcast.py) demonstrates this pattern for validating broadcasting logic, while [`backend/tests/test_screenshot.py`](https://github.com/abi/screenshot-to-code/blob/main/backend/tests/test_screenshot.py) provides examples of async HTTP client usage against the screenshot route.

## Type Checking Integration

Maintain type safety by running pyright before committing changes:

```bash
cd backend && poetry run pyright

```

This command scans changed files for type violations. The test files themselves are excluded from type checking unless they import from the backend package.

## Common Testing Issues

| Issue | Symptom | Resolution |
|-------|---------|------------|
| **Missing dev dependencies** | Import errors when running pytest | Run `poetry install` in the backend directory |
| **Async test failures** | `RuntimeError: Task <…> got destroyed` | Verify `asyncio_mode = auto` exists in [`backend/pytest.ini`](https://github.com/abi/screenshot-to-code/blob/main/backend/pytest.ini) |
| **Zero tests collected** | "collected 0 items" message | Ensure files are named `test_*.py` and located under `backend/tests/` |
| **Type errors** | pyright reports new violations | Update type hints or use `# type: ignore` sparingly |

## Summary

- The backend testing infrastructure relies on **pytest** and **pytest-asyncio** managed through Poetry.
- Configuration resides in [`backend/pytest.ini`](https://github.com/abi/screenshot-to-code/blob/main/backend/pytest.ini) with `asyncio_mode = auto` enabling seamless async test support without decorators.
- Tests live in `backend/tests/` following the `test_*.py` naming pattern.
- **pyright** provides static type checking via `poetry run pyright`.
- Reference implementations in [`test_status_broadcast.py`](https://github.com/abi/screenshot-to-code/blob/main/test_status_broadcast.py) and [`test_screenshot.py`](https://github.com/abi/screenshot-to-code/blob/main/test_screenshot.py) demonstrate patterns for testing FastAPI routes and async logic.

## Frequently Asked Questions

### What testing infrastructure is available for the Screenshot-to-Code backend?

The backend uses pytest as the primary test runner with pytest-asyncio plugin support for asynchronous tests. This infrastructure is configured through [`backend/pytest.ini`](https://github.com/abi/screenshot-to-code/blob/main/backend/pytest.ini) and dependency-managed via Poetry in [`backend/pyproject.toml`](https://github.com/abi/screenshot-to-code/blob/main/backend/pyproject.toml), enabling comprehensive testing of FastAPI endpoints and agent logic.

### How do I run the backend tests locally?

Navigate to the backend directory and execute `poetry run pytest` after installing dependencies with `poetry install`. This command automatically discovers tests in the `backend/tests/` directory and applies the async configuration from [`pytest.ini`](https://github.com/abi/screenshot-to-code/blob/main/pytest.ini) to handle both sync and async test functions.

### Can I write asynchronous tests without decorators?

Yes. Because [`backend/pytest.ini`](https://github.com/abi/screenshot-to-code/blob/main/backend/pytest.ini) sets `asyncio_mode = auto`, you can define test functions using `async def` without requiring the `@pytest.mark.asyncio` decorator. The pytest-asyncio plugin automatically detects and manages the event loop for these tests.

### Where are the example test files located?

Reference implementations are located at [`backend/tests/test_status_broadcast.py`](https://github.com/abi/screenshot-to-code/blob/main/backend/tests/test_status_broadcast.py) for broadcasting logic tests and [`backend/tests/test_screenshot.py`](https://github.com/abi/screenshot-to-code/blob/main/backend/tests/test_screenshot.py) for route testing. These files demonstrate patterns for both synchronous `TestClient` and asynchronous `AsyncClient` usage against the FastAPI app defined in [`backend/main.py`](https://github.com/abi/screenshot-to-code/blob/main/backend/main.py).