Skip to content
Development
Skill

/litestar-testing

Auto-activate for test_*.py, conftest.py, litestar.testing, TestClient, AsyncTestClient, create_test_client, create_async_test_client, anyio, Guard mocks, DI overrides, or handler tests. Not for generic pytest.

From plugin
litestar
1431 skills1 agent1 hook
Install
$ npx -y skills add litestar-org/litestar-skills --skill litestar-testing --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/litestar-testing

Context preview

The summary Claude sees to decide when to auto-load this skill.

Auto-activate for test_*.py, conftest.py, litestar.testing, TestClient, AsyncTestClient, create_test_client, create_async_test_client, anyio, Guard mocks, DI overrides, or handler tests. Not for generic pytest.

SKILL.md

litestar-testing.SKILL.md
name: litestar-testing
description: "Auto-activate for test_*.py, conftest.py, litestar.testing, TestClient, AsyncTestClient, create_test_client, create_async_test_client, anyio, Guard mocks, DI overrides, or handler tests. Not for generic pytest."

litestar-testing

Litestar-specific testing patterns built on pytest + anyio. Covers:

  • `TestClient` vs `AsyncTestClient` — when to use each
  • `@pytest.mark.anyio` setup
  • App + lifespan in tests
  • Fixture patterns from canonical [litestar-fullstack](https://github.com/litestar-org/litestar-fullstack) tests
  • Mocking Guards and DI dependencies
  • Integration with `pytest-databases` (see `../pytest-databases/SKILL.md`)
  • Autowire discovery and cache isolation (see `../litestar-autowire/references/testing.md`)
  • Request body / form / multipart / header / cookie testing
  • Litestar-specific assertion patterns (Response, headers, cookies)

For JS-side testing (Vitest, Testing Library, Playwright), use the upstream Vitest docs and Litestar's own JS examples. Out of scope here.

Code Style Rules

  • PEP 604 unions: `T | None`, never `Optional[T]`
  • Test modules MAY use `from __future__ import annotations` — they are pure consumer code.
  • Function-based tests (not class-based)
  • One assertion concern per test
  • Async Litestar tests use `@pytest.mark.anyio` by default; do not mix AnyIO and pytest-asyncio auto modes.
  • Prefer `AsyncTestClient` for new code; `TestClient` only for legacy / sync-only flows

Quick Reference

TestClient vs AsyncTestClient

| Client | When to Use | Lifespan | Internals | | --- | --- | --- | --- | | `TestClient` | Sync test bodies, simple smoke tests | Triggered via context manager | Runs ASGI in a thread pool | | `AsyncTestClient` | **Default for new tests** — async test bodies, lifespan-aware fixtures | Native async lifespan | Runs ASGI in the test event loop |

# AsyncTestClient — preferred
from litestar.testing import AsyncTestClient


async def test_index(async_client: AsyncTestClient):
    resp = await async_client.get("/")
    assert resp.status_code == 200
# TestClient — legacy / sync
from litestar.testing import TestClient


def test_index(client: TestClient):
    resp = client.get("/")
    assert resp.status_code == 200

anyio Setup

# conftest.py
import pytest


@pytest.fixture
def anyio_backend() -> str:
    return "asyncio"
# tests/test_x.py
import pytest


@pytest.mark.anyio
async def test_something(): ...

Litestar's runtime is anyio-based; do not use `pytest-asyncio` — it conflicts.

App + Lifespan Fixture

# conftest.py
from collections.abc import AsyncGenerator
import pytest
from litestar import Litestar
from litestar.testing import AsyncTestClient

from app import create_app


@pytest.fixture
async def app() -> Litestar:
    return create_app()


@pytest.fixture
async def async_client(app: Litestar) -> AsyncGenerator[AsyncTestClient, None]:
    async with AsyncTestClient(app=app) as client:
        yield client

`async with AsyncTestClient(...)` runs `on_startup` / `on_shutdown` hooks and plugin lifespans (Vite, SAQ, SQLAlchemy session pool, etc.). Without the context manager, lifespan does not fire.

Mocking Guards

Guards are functions of `(connection, route_handler) -> None`. Test the real guard with fake identity or authorization providers. Build a fresh app with replacement providers; Litestar has no mutable `app.dependency_overrides` registry.

from litestar.di import Provide


@pytest.fixture
async def async_client() -> AsyncGenerator[AsyncTestClient, None]:
    fake_users_service = FakeUserService()

    async def provide_fake_users_service() -> UserService:
        return fake_users_service

    test_app = create_app(
        dependencies={
            "users_service": Provide(provide_fake_users_service),
        },
    )
    async with AsyncTestClient(app=test_app) as client:
        yield client

Mocking DI Dependencies

from collections.abc import AsyncGenerator
from unittest.mock import AsyncMock

import pytest
from litestar.di import Provide
from litestar.testing import AsyncTestClient


@pytest.fixture
async def async_client() -> AsyncGenerator[tuple[AsyncTestClient, AsyncMock], None]:
    fake_email = AsyncMock()

    async def provide_fake_email() -> AsyncMock:
        return fake_email

    app = create_app(
        dependencies={
            "email_service": Provide(provide_fake_email),
        },
    )
    async with AsyncTestClient(app=app) as client:
        yield client, fake_email

For isolated handler tests, pass replacements directly to `create_async_test_client(..., dependencies={...})`. Do not mutate a constructed app; rebuilding preserves dependency resolution and prevents parallel tests from sharing overrides.

Integration with pytest-databases

Combine `pytest-databases` fixtures with the app fixture. See `../pytest-databases/SKILL.md`.

# conftest.py
pytest_plugins = ["pytest_databases.docker.postgres"]


@pytest.fixture
async def app(postgres_service) -> Litestar:
    from app import create_app
    from app.config import Settings

    settings = Settings(
        database_url=f"postgresql+asyncpg://{postgres_service.user}:{postgres_service.password}@{postgres_service.host}:{postgres_service.port}/{postgres_service.database}"
    )
    return create_app(settings=settings)

The `postgres_service` fixture starts a Postgres container. Inject its connection details into the app config.

Request Bodies

| Body Type | Pass via | | --- | --- | | JSON | `client.post("/", json={...})` | | Form | `client.post("/", data={...})` | | Multipart (file upload) | `client.post("/", files={"file": ("name.txt", b"content", "text/plain")})` | | Raw bytes | `client.post("/", content=b"...")` | | Custom content-type | `client.post("/", content=b"...", headers={"Content-Type": "..."})` |

async def test_create_user(async_client):
    r
Read more
Ships withlitestar

Opinionated, first-party agent skills, plugins, subagents, slash commands, and MCP servers for the Litestar framework and its ecosystem — publishable to every major AI agent and IDE from a single repo.

Get the whole plugin

Other skills on litestar.