{"id":"32f5445c-b211-41a3-bd83-7ae5fec02828","shortId":"9RNkGR","kind":"skill","title":"litestar-testing","tagline":"Auto-activate for test_*.py, conftest.py, litestar.testing imports, TestClient, AsyncTestClient, create_test_client, @pytest.mark.anyio, Guard mocks, DI overrides, or Litestar handler tests. Use when testing Litestar apps, handlers, lifespan, auth, HTMX, Inertia, or database-back","description":"# litestar-testing\n\nLitestar-specific testing patterns built on pytest + anyio. Covers:\n\n- `TestClient` vs `AsyncTestClient` — when to use each\n- `@pytest.mark.anyio` setup\n- App + lifespan in tests\n- Fixture patterns from canonical [litestar-fullstack](https://github.com/litestar-org/litestar-fullstack) tests\n- Mocking Guards and DI dependencies\n- Integration with `pytest-databases` (see `../pytest-databases/SKILL.md`)\n- Request body / form / multipart / header / cookie testing\n- Litestar-specific assertion patterns (Response, headers, cookies)\n\nFor JS-side testing (Vitest, Testing Library, Playwright), use the upstream Vitest docs and Litestar's own JS examples. Out of scope here.\n\n## Code Style Rules\n\n- PEP 604 unions: `T | None`, never `Optional[T]`\n- Test modules MAY use `from __future__ import annotations` — they are pure consumer code.\n- Function-based tests (not class-based)\n- One assertion concern per test\n- Async tests use `@pytest.mark.anyio` (not `@pytest.mark.asyncio`); Litestar uses anyio internally\n- Prefer `AsyncTestClient` for new code; `TestClient` only for legacy / sync-only flows\n\n## Quick Reference\n\n### TestClient vs AsyncTestClient\n\n| Client | When to Use | Lifespan | Internals |\n| --- | --- | --- | --- |\n| `TestClient` | Sync test bodies, simple smoke tests | Triggered via context manager | Runs ASGI in a thread pool |\n| `AsyncTestClient` | **Default for new tests** — async test bodies, lifespan-aware fixtures | Native async lifespan | Runs ASGI in the test event loop |\n\n```python\n# AsyncTestClient — preferred\nfrom litestar.testing import AsyncTestClient\n\nasync def test_index(async_client: AsyncTestClient):\n    resp = await async_client.get(\"/\")\n    assert resp.status_code == 200\n```\n\n```python\n# TestClient — legacy / sync\nfrom litestar.testing import TestClient\n\ndef test_index(client: TestClient):\n    resp = client.get(\"/\")\n    assert resp.status_code == 200\n```\n\n### anyio Setup\n\n```python\n# conftest.py\nimport pytest\n\n@pytest.fixture\ndef anyio_backend() -> str:\n    return \"asyncio\"\n```\n\n```python\n# tests/test_x.py\nimport pytest\n\n@pytest.mark.anyio\nasync def test_something():\n    ...\n```\n\nLitestar's runtime is anyio-based; do not use `pytest-asyncio` — it conflicts.\n\n### App + Lifespan Fixture\n\n```python\n# conftest.py\nfrom collections.abc import AsyncGenerator\nimport pytest\nfrom litestar import Litestar\nfrom litestar.testing import AsyncTestClient\n\nfrom app import create_app\n\n\n@pytest.fixture\nasync def app() -> Litestar:\n    return create_app()\n\n\n@pytest.fixture\nasync def async_client(app: Litestar) -> AsyncGenerator[AsyncTestClient, None]:\n    async with AsyncTestClient(app=app) as client:\n        yield client\n```\n\n`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.\n\n### Mocking Guards\n\nGuards are functions of `(connection, route_handler) -> None`. Mock by overriding `dependencies` or by registering a no-op guard at the app level for tests:\n\n```python\n# conftest.py\nfrom litestar import Litestar\n\nfrom app import create_app\n\n\n@pytest.fixture\nasync def app_with_no_auth() -> Litestar:\n    \"\"\"App with auth Guard replaced by a no-op for tests.\"\"\"\n    from app.domain.accounts.guards import requires_active_user\n\n    async def allow_all(connection, route_handler) -> None:\n        return None\n\n    app = create_app()\n    # Swap the guard everywhere it's referenced (depends on app structure)\n    for route in app.route_handler_method_map.values():\n        ...\n    return app\n```\n\nCleaner: use DI override (preferred). If the Guard depends on a service via DI, override the service:\n\n```python\n@pytest.fixture\nasync def async_client(app: Litestar) -> AsyncGenerator[AsyncTestClient, None]:\n    from app.domain.accounts.services import UserService\n\n    class FakeUserService(UserService): ...\n\n    app.dependencies[\"users_service\"] = lambda: FakeUserService(...)\n    async with AsyncTestClient(app=app) as client:\n        yield client\n```\n\n### Mocking DI Dependencies\n\n```python\nfrom unittest.mock import AsyncMock\n\n@pytest.fixture\nasync def async_client(app: Litestar) -> AsyncGenerator[AsyncTestClient, None]:\n    fake_email = AsyncMock()\n    app.dependencies[\"email_service\"] = lambda: fake_email\n    async with AsyncTestClient(app=app) as client:\n        yield client, fake_email\n```\n\n### Integration with pytest-databases\n\nCombine `pytest-databases` fixtures with the app fixture. See `../pytest-databases/SKILL.md`.\n\n```python\n# conftest.py\npytest_plugins = [\"pytest_databases.docker.postgres\"]\n\n\n@pytest.fixture\nasync def app(postgres_service) -> Litestar:\n    from app import create_app\n    from app.config import Settings\n\n    settings = Settings(database_url=f\"postgresql+asyncpg://{postgres_service.user}:{postgres_service.password}@{postgres_service.host}:{postgres_service.port}/{postgres_service.database}\")\n    return create_app(settings=settings)\n```\n\nThe `postgres_service` fixture starts a Postgres container. Inject its connection details into the app config.\n\n### Request Bodies\n\n| Body Type | Pass via |\n| --- | --- |\n| JSON | `client.post(\"/\", json={...})` |\n| Form | `client.post(\"/\", data={...})` |\n| Multipart (file upload) | `client.post(\"/\", files={\"file\": (\"name.txt\", b\"content\", \"text/plain\")})` |\n| Raw bytes | `client.post(\"/\", content=b\"...\")` |\n| Custom content-type | `client.post(\"/\", content=b\"...\", headers={\"Content-Type\": \"...\"})` |\n\n```python\nasync def test_create_user(async_client):\n    resp = await async_client.post(\n        \"/api/users\",\n        json={\"name\": \"Alice\", \"email\": \"alice@example.com\"},\n    )\n    assert resp.status_code == 201\n    body = resp.json()\n    assert body[\"name\"] == \"Alice\"\n```\n\n### Headers, Cookies, Auth\n\n```python\n# Header\nresp = await async_client.get(\"/\", headers={\"Authorization\": \"Bearer token\"})\n\n# Cookie\nasync_client.cookies.set(\"session\", \"abc123\")\nresp = await async_client.get(\"/\")\n\n# Per-request cookies\nresp = await async_client.get(\"/\", cookies={\"session\": \"abc123\"})\n```\n\n### HTMX Requests\n\n```python\nasync def test_htmx_partial(async_client):\n    resp = await async_client.get(\n        \"/items/list\",\n        headers={\"HX-Request\": \"true\", \"HX-Target\": \"#item-list\"},\n    )\n    assert resp.status_code == 200\n    assert \"<ul\" in resp.text\n```\n\n### Response Assertions\n\n```python\n# Status\nassert resp.status_code == 200\n\n# Body\nassert resp.json() == {\"id\": 1, \"name\": \"Alice\"}\n\n# Headers\nassert resp.headers[\"content-type\"].startswith(\"application/json\")\nassert \"HX-Trigger\" in resp.headers\n\n# Cookies (set by server)\nassert \"session\" in resp.cookies\n```\n\n### Parametrize\n\n```python\nimport pytest\n\n@pytest.mark.parametrize(\"payload, expected_status\", [\n    ({\"name\": \"valid\", \"email\": \"a@b.co\"}, 201),\n    ({\"name\": \"\", \"email\": \"a@b.co\"}, 400),\n    ({\"name\": \"valid\", \"email\": \"not-email\"}, 400),\n])\n@pytest.mark.anyio\nasync def test_create_user_validation(async_client, payload, expected_status):\n    resp = await async_client.post(\"/api/users\", json=payload)\n    assert resp.status_code == expected_status\n```\n\n### Coverage\n\n```bash\npytest --cov=src --cov-report=html\npytest --cov=src --cov-fail-under=90\n```\n\n<workflow>\n\n## Workflow\n\n### Step 1: Set Up anyio Backend\n\nAdd `anyio_backend` fixture to `conftest.py` returning `\"asyncio\"`. Mark async tests with `@pytest.mark.anyio`.\n\n### Step 2: App + Client Fixtures\n\nBuild an `app` fixture that returns a fresh `Litestar` instance per test (or per session if no shared state). Build an `async_client` fixture that wraps the app in `AsyncTestClient` via `async with`.\n\n### Step 3: Add Database Fixtures\n\nIf the app talks to a DB, layer in `pytest-databases` (`postgres_service`, `mysql_service`, etc.) and pass connection details into the app config. See `../pytest-databases/SKILL.md`.\n\n### Step 4: Override DI for Externals\n\nMock `EmailService`, HTTP clients, and other side-effect-laden dependencies via `app.dependencies[name] = lambda: fake`. Avoid real network calls in tests.\n\n### Step 5: Mock Guards When Needed\n\nFor tests that should bypass auth, override the Guard's underlying service or register a no-op Guard. Prefer DI overrides over patching internals.\n\n### Step 6: Write Tests\n\n- One assertion concern per test.\n- Use `@pytest.mark.parametrize` for input variations.\n- Use `AsyncTestClient` for new code.\n- Include HTMX / Inertia headers when testing those paths.\n\n### Step 7: Verify Coverage\n\n`pytest --cov=src --cov-fail-under=90`. Cover handlers, services, Guards, and at least one happy-path + one error-path per route.\n\n</workflow>\n\n<guardrails>\n\n## Guardrails\n\n- **Use `@pytest.mark.anyio`, not `@pytest.mark.asyncio`** — Litestar runs on anyio. Mixing breaks lifespan.\n- **Always `async with AsyncTestClient(app=app)`** — without the context manager, plugin lifespans (Vite, SAQ, SQLAlchemy) never run, and tests see a half-initialized app.\n- **Prefer `AsyncTestClient` over `TestClient`** for new tests — the async client matches Litestar's runtime model.\n- **Mock side effects via DI override**, not patching — keeps tests isolated from import order and global state.\n- **Use `pytest-databases` for real DB testing** — never mock SQLAlchemy / sqlspec internals; assertions on mocked queries don't catch real bugs.\n- **Function-based tests** — no class-based test containers unless absolutely needed for shared setup.\n- **One assertion concern per test** — failures should pinpoint a single behavior.\n- **Don't share state between tests** — fresh app + fresh DB per test (or per module with explicit cleanup).\n- **Test the HTMX path with `HX-Request: true`** — handlers that branch on `request.htmx` need both branches covered.\n- **Mock email via `InMemoryConfig`** — see `../litestar-email/SKILL.md`.\n\n</guardrails>\n\n<validation>\n\n### Validation Checkpoint\n\nBefore delivering Litestar tests, verify:\n\n- [ ] `anyio_backend` fixture returns `\"asyncio\"`\n- [ ] Async tests use `@pytest.mark.anyio`\n- [ ] `AsyncTestClient` is wrapped in `async with` (lifespan fires)\n- [ ] DI dependencies (email, HTTP clients) are overridden, not patched\n- [ ] DB-dependent tests use `pytest-databases` fixtures\n- [ ] Guards either pass real auth (with a fixture user) or are bypassed via DI override\n- [ ] One assertion concern per test; parametrize for input variations\n- [ ] HTMX-targeted handlers have tests with `HX-Request: true`\n- [ ] Coverage gate (`--cov-fail-under`) is set in CI\n\n</validation>\n\n<example>\n\n## Example\n\n**Task:** Test an account creation endpoint that hits Postgres, sends a welcome email via SAQ, and is guarded by an auth check.\n\n```python\n# conftest.py\nfrom collections.abc import AsyncGenerator\nimport pytest\nfrom unittest.mock import AsyncMock\nfrom litestar import Litestar\nfrom litestar.testing import AsyncTestClient\n\npytest_plugins = [\"pytest_databases.docker.postgres\"]\n\n\n@pytest.fixture\ndef anyio_backend() -> str:\n    return \"asyncio\"\n\n\n@pytest.fixture\nasync def app(postgres_service) -> Litestar:\n    from app import create_app\n    from app.config import Settings\n\n    settings = Settings(\n        database_url=(\n            f\"postgresql+asyncpg://{postgres_service.user}:{postgres_service.password}\"\n            f\"@{postgres_service.host}:{postgres_service.port}/{postgres_service.database}\"\n        ),\n    )\n    return create_app(settings=settings)\n\n\n@pytest.fixture\nasync def async_client(app: Litestar) -> AsyncGenerator[tuple[AsyncTestClient, AsyncMock], None]:\n    fake_queue = AsyncMock()\n    app.dependencies[\"task_queues\"] = lambda: type(\"Q\", (), {\"get\": lambda self, name: fake_queue})()\n\n    async with AsyncTestClient(app=app) as client:\n        yield client, fake_queue\n```\n\n```python\n# tests/test_accounts.py\nimport pytest\n\n\n@pytest.mark.anyio\nasync def test_create_account_persists_and_queues_email(async_client):\n    client, fake_queue = async_client\n\n    resp = await client.post(\n        \"/api/accounts\",\n        json={\"email\": \"alice@example.com\", \"name\": \"Alice\"},\n    )\n\n    assert resp.status_code == 201\n    body = resp.json()\n    assert body[\"email\"] == \"alice@example.com\"\n    fake_queue.enqueue.assert_awaited_once()\n    args, kwargs = fake_queue.enqueue.await_args\n    assert args[0] == \"send_welcome_email\"\n    assert kwargs[\"email\"] == \"alice@example.com\"\n\n\n@pytest.mark.anyio\n@pytest.mark.parametrize(\"payload, expected_status\", [\n    ({\"email\": \"valid@example.com\", \"name\": \"Valid\"}, 201),\n    ({\"email\": \"\", \"name\": \"Valid\"}, 400),\n    ({\"email\": \"valid@example.com\", \"name\": \"\"}, 400),\n])\nasync def test_create_account_validation(async_client, payload, expected_status):\n    client, _ = async_client\n    resp = await client.post(\"/api/accounts\", json=payload)\n    assert resp.status_code == expected_status\n```\n\n</example>\n\n---\n\n## References Index\n\n- **[Async Testing](references/async_testing.md)** — anyio + pytest-anyio setup, async fixtures, context manager testing, and common pitfalls.\n\n## Cross-References\n\n- **[litestar](../litestar/SKILL.md)** — Litestar fundamentals.\n- **[pytest-databases](../pytest-databases/SKILL.md)** — Container-based DB fixtures.\n- **[litestar-email](../litestar-email/SKILL.md)** — `InMemoryConfig` for email tests.\n- **[litestar-saq](../litestar-saq/SKILL.md)** — Mocking task queues.\n\n## JS-side Testing\n\nFor Vitest, Testing Library (React/Vue), and component testing, refer to upstream Vitest docs (<https://vitest.dev/>). This skill covers the Python/Litestar side only.\n\n## Official References\n\n- <https://docs.litestar.dev/2/usage/testing.html>\n- <https://docs.pytest.org/en/stable/>\n- <https://anyio.readthedocs.io/en/stable/testing.html>\n\n## Shared Styleguide Baseline\n\n- [General Principles](../litestar-styleguide/references/general.md)\n- [Testing](../litestar-styleguide/references/testing.md)\n- [Python](../litestar-styleguide/references/python.md)\n- [Litestar](../litestar-styleguide/references/litestar.md)","tags":["litestar","testing","skills","litestar-org","advanced-alchemy","agent-skills","agentskills","ai-agents","claude-code-plugin","claude-code-skills","gemini-cli-extension","htmx"],"capabilities":["skill","source-litestar-org","skill-litestar-testing","topic-advanced-alchemy","topic-agent-skills","topic-agentskills","topic-ai-agents","topic-claude-code-plugin","topic-claude-code-skills","topic-gemini-cli-extension","topic-htmx","topic-inertia","topic-litestar","topic-mcp","topic-python"],"categories":["litestar-skills"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/litestar-org/litestar-skills/litestar-testing","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add litestar-org/litestar-skills","source_repo":"https://github.com/litestar-org/litestar-skills","install_from":"skills.sh"}},"qualityScore":"0.453","qualityRationale":"deterministic score 0.45 from registry signals: · indexed on github topic:agent-skills · 7 github stars · SKILL.md body (13,882 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-05-18T19:13:54.952Z","embedding":null,"createdAt":"2026-05-18T13:20:58.884Z","updatedAt":"2026-05-18T19:13:54.952Z","lastSeenAt":"2026-05-18T19:13:54.952Z","tsv":"'/2/usage/testing.html':1626 '/api/accounts':1472,1540 '/api/users':693,847 '/en/stable/':1629 '/en/stable/testing.html':1632 '/items/list':751 '/litestar-email/skill.md':1236,1585 '/litestar-org/litestar-fullstack)':76 '/litestar-saq/skill.md':1593 '/litestar-styleguide/references/general.md':1638 '/litestar-styleguide/references/litestar.md':1644 '/litestar-styleguide/references/python.md':1642 '/litestar-styleguide/references/testing.md':1640 '/litestar/skill.md':1570 '/pytest-databases/skill.md':89,590,961,1576 '0':1497 '1':783,874 '2':893 '200':259,278,766,778 '201':702,820,1481,1514 '3':931 '4':963 '400':824,831,1518,1522 '5':991 '6':1022 '604':133 '7':1049 '90':871,1059 'a@b.co':819,823 'abc123':724,737 'absolut':1179 'account':1328,1457,1527 'activ':6,456 'add':879,932 'alic':696,708,785,1477 'alice@example.com':698,1475,1487,1504 'allow':460 'alway':1089 'annot':147 'anyio':52,174,279,287,306,877,880,1085,1244,1372,1553,1556 'anyio-bas':305 'anyio.readthedocs.io':1631 'anyio.readthedocs.io/en/stable/testing.html':1630 'app':31,63,316,336,339,343,347,353,361,362,417,428,431,435,440,468,470,480,487,511,531,532,550,567,568,587,599,604,607,625,642,894,899,924,937,958,1093,1094,1113,1202,1380,1385,1388,1407,1415,1440,1441 'app.config':609,1390 'app.dependencies':523,558,980,1425 'app.domain.accounts.guards':453 'app.domain.accounts.services':517 'app.route_handler_method_map.values':485 'application/json':793 'arg':1491,1494,1496 'asgi':212,233 'assert':100,162,256,275,699,705,763,767,772,775,780,787,794,804,850,1026,1159,1185,1295,1478,1484,1495,1501,1543 'async':166,222,230,246,250,297,341,349,351,358,367,433,458,507,509,528,546,548,564,597,683,688,741,746,833,839,888,918,928,1090,1122,1249,1257,1378,1411,1413,1437,1453,1462,1467,1523,1529,1535,1550,1558 'async_client.cookies.set':722 'async_client.get':255,716,727,734,750 'async_client.post':692,846 'asyncgener':324,355,513,552,1352,1417 'asyncio':291,313,886,1248,1376 'asyncmock':544,557,1358,1420,1424 'asynctestcli':14,56,177,193,217,240,245,252,334,356,360,369,514,530,553,566,926,1036,1092,1115,1253,1366,1419,1439 'auth':34,438,442,711,1001,1283,1345 'author':718 'auto':5 'auto-activ':4 'avoid':984 'await':254,691,715,726,733,749,845,1470,1489,1538 'awar':227 'b':663,670,677 'back':40 'backend':288,878,881,1245,1373 'base':155,160,307,1170,1175,1579 'baselin':1635 'bash':856 'bearer':719 'behavior':1194 'bodi':91,203,224,645,646,703,706,779,1482,1485 'branch':1224,1229 'break':1087 'bug':1167 'build':897,916 'built':49 'bypass':1000,1290 'byte':667 'call':987 'canon':70 'catch':1165 'check':1346 'checkpoint':1238 'ci':1323 'class':159,520,1174 'class-bas':158,1173 'cleaner':488 'cleanup':1212 'client':17,194,251,271,352,364,366,510,534,536,549,570,572,689,747,840,895,919,971,1123,1265,1414,1443,1445,1463,1464,1468,1530,1534,1536 'client.get':274 'client.post':651,654,659,668,675,1471,1539 'code':129,152,180,258,277,701,765,777,852,1039,1480,1545 'collections.abc':322,1350 'combin':580 'common':1564 'compon':1607 'concern':163,1027,1186,1296 'config':643,959 'conflict':315 'conftest.py':10,282,320,422,592,884,1348 'connect':399,462,638,954 'consum':151 'contain':635,1177,1578 'container-bas':1577 'content':664,669,673,676,680,790 'content-typ':672,679,789 'context':209,387,1097,1560 'cooki':95,104,710,721,731,735,800 'cov':858,861,865,868,1053,1056,1317 'cov-fail-und':867,1055,1316 'cov-report':860 'cover':53,1060,1230,1617 'coverag':855,1051,1314 'creat':15,338,346,430,469,606,624,686,836,1387,1406,1456,1526 'creation':1329 'cross':1567 'cross-refer':1566 'custom':671 'data':655 'databas':39,87,579,583,614,933,946,1149,1277,1395,1575 'database-back':38 'db':941,1152,1204,1271,1580 'db-depend':1270 'def':247,268,286,298,342,350,434,459,508,547,598,684,742,834,1371,1379,1412,1454,1524 'default':218 'deliv':1240 'depend':82,406,478,496,539,978,1262,1272 'detail':639,955 'di':21,81,490,501,538,965,1016,1133,1261,1292 'doc':118,1613 'docs.litestar.dev':1625 'docs.litestar.dev/2/usage/testing.html':1624 'docs.pytest.org':1628 'docs.pytest.org/en/stable/':1627 'effect':976,1131 'either':1280 'email':556,559,563,574,697,818,822,827,830,1232,1263,1337,1461,1474,1486,1500,1503,1510,1515,1519,1584,1588 'emailservic':969 'endpoint':1330 'error':1073 'error-path':1072 'etc':384,951 'event':237 'everywher':474 'exampl':124,1324 'expect':814,842,853,1508,1532,1546 'explicit':1211 'extern':967 'f':616,1397,1401 'fail':869,1057,1318 'failur':1189 'fake':555,562,573,983,1422,1435,1446,1465 'fake_queue.enqueue.assert':1488 'fake_queue.enqueue.await':1493 'fakeuserservic':521,527 'file':657,660,661 'fire':392,1260 'fixtur':67,228,318,584,588,631,882,896,900,920,934,1246,1278,1286,1559,1581 'flow':188 'form':92,653 'fresh':904,1201,1203 'fullstack':73 'function':154,397,1169 'function-bas':153,1168 'fundament':1572 'futur':145 'gate':1315 'general':1636 'get':1431 'github.com':75 'github.com/litestar-org/litestar-fullstack)':74 'global':1144 'guard':19,79,394,395,414,443,473,495,993,1004,1014,1063,1279,1342 'guardrail':1077 'half':1111 'half-initi':1110 'handler':25,32,401,464,1061,1222,1306 'happi':1069 'happy-path':1068 'header':94,103,678,709,713,717,752,786,1043 'hit':1332 'hook':375 'html':863 'htmx':35,738,744,1041,1215,1304 'htmx-target':1303 'http':970,1264 'hx':754,758,796,1219,1311 'hx-request':753,1218,1310 'hx-target':757 'hx-trigger':795 'id':782 'import':12,146,244,266,283,294,323,325,329,333,337,425,429,454,518,543,605,610,810,1141,1351,1353,1357,1361,1365,1386,1391,1450 'includ':1040 'index':249,270,1549 'inertia':36,1042 'initi':1112 'inject':636 'inmemoryconfig':1234,1586 'input':1033,1301 'instanc':906 'integr':83,575 'intern':175,199,1020,1158 'isol':1139 'item':761 'item-list':760 'js':107,123,1598 'js-side':106,1597 'json':650,652,694,848,1473,1541 'keep':1137 'kwarg':1492,1502 'laden':977 'lambda':526,561,982,1428,1432 'layer':942 'least':1066 'legaci':184,262 'level':418 'librari':112,1604 'lifespan':33,64,198,226,231,317,378,389,1088,1100,1259 'lifespan-awar':225 'list':762 'litestar':2,24,30,42,45,72,98,120,172,301,328,330,344,354,424,426,439,512,551,602,905,1082,1125,1241,1360,1362,1383,1416,1569,1571,1583,1591,1643 'litestar-email':1582 'litestar-fullstack':71 'litestar-saq':1590 'litestar-specif':44,97 'litestar-test':1,41 'litestar.testing':11,243,265,332,1364 'loop':238 'manag':210,388,1098,1561 'mark':887 'match':1124 'may':142 'mix':1086 'mock':20,78,393,403,537,968,992,1129,1155,1161,1231,1594 'model':1128 'modul':141,1209 'multipart':93,656 'mysql':949 'name':695,707,784,816,821,825,981,1434,1476,1512,1516,1521 'name.txt':662 'nativ':229 'need':995,1180,1227 'network':986 'never':137,1104,1154 'new':179,220,1038,1119 'no-op':411,447,1011 'none':136,357,402,465,467,515,554,1421 'not-email':828 'offici':1622 'one':161,1025,1067,1071,1184,1294 'op':413,449,1013 'option':138 'order':1142 'overrid':22,405,491,502,964,1002,1017,1134,1293 'overridden':1267 'parametr':808,1299 'partial':745 'pass':648,953,1281 'patch':1019,1136,1269 'path':1047,1070,1074,1216 'pattern':48,68,101 'payload':813,841,849,1507,1531,1542 'pep':132 'per':164,729,907,910,1028,1075,1187,1205,1208,1297 'per-request':728 'persist':1458 'pinpoint':1191 'pitfal':1565 'playwright':113 'plugin':377,594,1099,1368 'pool':216,383 'postgr':600,629,634,947,1333,1381 'postgres_service.database':622,1404 'postgres_service.host':620,1402 'postgres_service.password':619,1400 'postgres_service.port':621,1403 'postgres_service.user':618,1399 'postgresql':617,1398 'prefer':176,241,492,1015,1114 'principl':1637 'pure':150 'py':9 'pytest':51,86,284,295,312,326,578,582,593,811,857,864,945,1052,1148,1276,1354,1367,1451,1555,1574 'pytest-anyio':1554 'pytest-asyncio':311 'pytest-databas':85,577,581,944,1147,1275,1573 'pytest.fixture':285,340,348,432,506,545,596,1370,1377,1410 'pytest.mark.anyio':18,61,169,296,832,891,1079,1252,1452,1505 'pytest.mark.asyncio':171,1081 'pytest.mark.parametrize':812,1031,1506 'pytest_databases.docker.postgres':595,1369 'python':239,260,281,292,319,421,505,540,591,682,712,740,773,809,1347,1448,1641 'python/litestar':1619 'q':1430 'queri':1162 'queue':1423,1427,1436,1447,1460,1466,1596 'quick':189 'raw':666 'react/vue':1605 'real':985,1151,1166,1282 'refer':190,1548,1568,1609,1623 'referenc':477 'references/async_testing.md':1552 'regist':409,1009 'replac':444 'report':862 'request':90,644,730,739,755,1220,1312 'request.htmx':1226 'requir':455 'resp':253,273,690,714,725,732,748,844,1469,1537 'resp.cookies':807 'resp.headers':788,799 'resp.json':704,781,1483 'resp.status':257,276,700,764,776,851,1479,1544 'resp.text':770 'respons':102,771 'return':290,345,466,486,623,885,902,1247,1375,1405 'rout':400,463,483,1076 'rule':131 'run':211,232,370,1083,1105 'runtim':303,1127 'saq':380,1102,1339,1592 'scope':127 'see':88,589,960,1108,1235 'self':1433 'send':1334,1498 'server':803 'servic':499,504,525,560,601,630,948,950,1007,1062,1382 'session':382,723,736,805,911 'set':611,612,613,626,627,801,875,1321,1392,1393,1394,1408,1409 'setup':62,280,1183,1557 'share':914,1182,1197,1633 'shutdown':374 'side':108,975,1130,1599,1620 'side-effect-laden':974 'simpl':204 'singl':1193 'skill':1616 'skill-litestar-testing' 'smoke':205 'someth':300 'source-litestar-org' 'specif':46,99 'sqlalchemi':381,1103,1156 'sqlspec':1157 'src':859,866,1054 'start':632 'startswith':792 'startup':372 'state':915,1145,1198 'status':774,815,843,854,1509,1533,1547 'step':873,892,930,962,990,1021,1048 'str':289,1374 'structur':481 'style':130 'styleguid':1634 'swap':471 'sync':186,201,263 'sync-on':185 'talk':938 'target':759,1305 'task':1325,1426,1595 'test':3,8,16,26,29,43,47,66,77,96,109,111,140,156,165,167,202,206,221,223,236,248,269,299,420,451,685,743,835,889,908,989,997,1024,1029,1045,1107,1120,1138,1153,1171,1176,1188,1200,1206,1213,1242,1250,1273,1298,1308,1326,1455,1525,1551,1562,1589,1600,1603,1608,1639 'testclient':13,54,181,191,200,261,267,272,1117 'tests/test_accounts.py':1449 'tests/test_x.py':293 'text/plain':665 'thread':215 'token':720 'topic-advanced-alchemy' 'topic-agent-skills' 'topic-agentskills' 'topic-ai-agents' 'topic-claude-code-plugin' 'topic-claude-code-skills' 'topic-gemini-cli-extension' 'topic-htmx' 'topic-inertia' 'topic-litestar' 'topic-mcp' 'topic-python' 'trigger':207,797 'true':756,1221,1313 'tupl':1418 'type':647,674,681,791,1429 'ul':768 'under':1006 'union':134 'unittest.mock':542,1356 'unless':1178 'upload':658 'upstream':116,1611 'url':615,1396 'use':27,59,114,143,168,173,197,310,489,1030,1035,1078,1146,1251,1274 'user':457,524,687,837,1287 'userservic':519,522 'valid':817,826,838,1237,1513,1517,1528 'valid@example.com':1511,1520 'variat':1034,1302 'verifi':1050,1243 'via':208,500,649,927,979,1132,1233,1291,1338 'vite':379,1101 'vitest':110,117,1602,1612 'vitest.dev':1614 'vs':55,192 'welcom':1336,1499 'without':385,1095 'workflow':872 'wrap':922,1255 'write':1023 'yield':365,535,571,1444","prices":[{"id":"709c2459-5ede-49d3-a214-ed796ee9b02f","listingId":"32f5445c-b211-41a3-bd83-7ae5fec02828","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"litestar-org","category":"litestar-skills","install_from":"skills.sh"},"createdAt":"2026-05-18T13:20:58.884Z"}],"sources":[{"listingId":"32f5445c-b211-41a3-bd83-7ae5fec02828","source":"github","sourceId":"litestar-org/litestar-skills/litestar-testing","sourceUrl":"https://github.com/litestar-org/litestar-skills/tree/main/skills/litestar-testing","isPrimary":false,"firstSeenAt":"2026-05-18T13:20:58.884Z","lastSeenAt":"2026-05-18T19:13:54.952Z"}],"details":{"listingId":"32f5445c-b211-41a3-bd83-7ae5fec02828","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"litestar-org","slug":"litestar-testing","github":{"repo":"litestar-org/litestar-skills","stars":7,"topics":["advanced-alchemy","agent-skills","agentskills","ai-agents","claude-code-plugin","claude-code-skills","gemini-cli-extension","htmx","inertia","litestar","mcp","python","sqlspec"],"license":"mit","html_url":"https://github.com/litestar-org/litestar-skills","pushed_at":"2026-05-13T16:04:09Z","description":"Opinionated first-party agent skills, plugins, subagents, slash commands, and MCP servers for the Litestar framework ecosystem — publishable to Claude Code, Gemini CLI, Codex CLI, Cursor, OpenCode, and VS Code/Copilot from a single repo.","skill_md_sha":"e1f47c2d291bdc7f248f1e65ec14d1c1c3d49e3f","skill_md_path":"skills/litestar-testing/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/litestar-org/litestar-skills/tree/main/skills/litestar-testing"},"layout":"multi","source":"github","category":"litestar-skills","frontmatter":{"name":"litestar-testing","description":"Auto-activate for test_*.py, conftest.py, litestar.testing imports, TestClient, AsyncTestClient, create_test_client, @pytest.mark.anyio, Guard mocks, DI overrides, or Litestar handler tests. Use when testing Litestar apps, handlers, lifespan, auth, HTMX, Inertia, or database-backed integration flows. Not for generic pytest, Vitest, or non-Litestar test suites."},"skills_sh_url":"https://skills.sh/litestar-org/litestar-skills/litestar-testing"},"updatedAt":"2026-05-18T19:13:54.952Z"}}