Repository: litestar-org/litestar

Issue:
Refactor: Reorganise test suite
Our test suite has grown with the project, but as a result has become a bit disorganised in quite a few places. It should be refactored in a way that structures it in a more consistent and logical way.


Discussion:

Resolving patch:
diff --git a/docs/examples/conftest.py b/docs/examples/conftest.py
deleted file mode 100644
--- a/docs/examples/conftest.py
+++ /dev/null
@@ -1,25 +0,0 @@
-import logging
-import os
-from typing import Generator
-
-import pytest
-
-
-@pytest.fixture()
-def reset_httpx_logging() -> Generator[None, None, None]:
-    # ensure that httpx logging is not interfering with our test client
-    httpx_logger = logging.getLogger("httpx")
-    initial_level = httpx_logger.level
-    httpx_logger.setLevel(logging.WARNING)
-    yield
-    httpx_logger.setLevel(initial_level)
-
-
-# the monkeypatch fixture does not work with session scoped dependencies
-@pytest.fixture(autouse=True, scope="session")
-def disable_warn_implicit_sync_to_thread() -> Generator[None, None, None]:
-    old_value = os.getenv("LITESTAR_WARN_IMPLICIT_SYNC_TO_THREAD")
-    os.environ["LITESTAR_WARN_IMPLICIT_SYNC_TO_THREAD"] = "0"
-    yield
-    if old_value is not None:
-        os.environ["LITESTAR_WARN_IMPLICIT_SYNC_TO_THREAD"] = old_value


Test patch:
diff --git a/docs/examples/tests/test_request_data.py b/docs/examples/tests/test_request_data.py
deleted file mode 100644
--- a/docs/examples/tests/test_request_data.py
+++ /dev/null
@@ -1,11 +0,0 @@
-from examples.request_data.msgpack_request import app as msgpack_app
-from litestar.serialization import encode_msgpack
-from litestar.testing import TestClient
-
-
-def test_msgpack_app() -> None:
-    test_data = {"name": "Moishe Zuchmir", "age": 30, "programmer": True}
-
-    with TestClient(app=msgpack_app) as client:
-        response = client.post("/", content=encode_msgpack(test_data))
-        assert response.json() == test_data
diff --git a/test_apps/openapi_test_app/main.py b/test_apps/openapi_test_app/main.py
--- a/test_apps/openapi_test_app/main.py
+++ b/test_apps/openapi_test_app/main.py
@@ -1,7 +1,7 @@
 from typing import Dict
 
 from litestar import Litestar, get
-from tests.openapi.conftest import create_person_controller, create_pet_controller
+from tests.unit.test_openapi.conftest import create_person_controller, create_pet_controller
 
 
 @get("/")
diff --git a/test_apps/piccolo_admin_test_app/home/tables.py b/test_apps/piccolo_admin_test_app/home/tables.py
--- a/test_apps/piccolo_admin_test_app/home/tables.py
+++ b/test_apps/piccolo_admin_test_app/home/tables.py
@@ -2,7 +2,6 @@
 from piccolo.columns import Boolean, ForeignKey, Timestamp, Varchar
 from piccolo.columns.readable import Readable
 from piccolo.table import Table
-
 from piccolo_conf import DB
 
 
diff --git a/tests/app/test_app.py b/tests/app/test_app.py
deleted file mode 100644
--- a/tests/app/test_app.py
+++ /dev/null
@@ -1,67 +0,0 @@
-from __future__ import annotations
-
-import logging
-
-import pytest
-from pytest import MonkeyPatch
-
-from litestar import Litestar
-from litestar.exceptions import ImproperlyConfiguredException, LitestarWarning
-
-
-def test_access_openapi_schema_raises_if_not_configured() -> None:
-    """Test that accessing the openapi schema raises if not configured."""
-    app = Litestar(openapi_config=None)
-    with pytest.raises(ImproperlyConfiguredException):
-        app.openapi_schema
-
-
-def test_set_debug_updates_logging_level() -> None:
-    app = Litestar()
-
-    assert app.logger is not None
-    assert app.logger.level == logging.INFO  # type: ignore[attr-defined]
-
-    app.debug = True
-    assert app.logger.level == logging.DEBUG  # type: ignore[attr-defined]
-
-    app.debug = False
-    assert app.logger.level == logging.INFO  # type: ignore[attr-defined]
-
-
-@pytest.mark.parametrize("env_name,app_attr", [("LITESTAR_DEBUG", "debug"), ("LITESTAR_PDB", "pdb_on_exception")])
-@pytest.mark.parametrize(
-    "env_value,app_value,expected_value",
-    [
-        (None, None, False),
-        (None, False, False),
-        (None, True, True),
-        ("0", None, False),
-        ("0", False, False),
-        ("0", True, True),
-        ("1", None, True),
-        ("1", False, False),
-        ("1", True, True),
-    ],
-)
-def test_set_env_flags(
-    monkeypatch: MonkeyPatch,
-    env_value: str | None,
-    app_value: bool | None,
-    expected_value: bool,
-    env_name: str,
-    app_attr: str,
-) -> None:
-    if env_value is not None:
-        monkeypatch.setenv(env_name, env_value)
-    else:
-        monkeypatch.delenv(env_name, raising=False)
-
-    app = Litestar(**{app_attr: app_value})  # type: ignore[arg-type]
-
-    assert getattr(app, app_attr) is expected_value
-
-
-def test_warn_pdb_on_exception() -> None:
-    with pytest.warns(LitestarWarning, match="Debugger"):
-        Litestar(pdb_on_exception=True)
diff --git a/tests/app/test_app_config.py b/tests/app/test_app_config.py
deleted file mode 100644
--- a/tests/app/test_app_config.py
+++ /dev/null
@@ -1,143 +0,0 @@
-import inspect
-from dataclasses import fields
-from typing import List, Tuple
-from unittest.mock import MagicMock, Mock, PropertyMock
-
-import pytest
-
-from litestar.app import Litestar
-from litestar.config.app import AppConfig
-from litestar.config.response_cache import ResponseCacheConfig
-from litestar.datastructures import State
-from litestar.events.emitter import SimpleEventEmitter
-from litestar.logging.config import LoggingConfig
-from litestar.router import Router
-
-
-@pytest.fixture()
-def app_config_object() -> AppConfig:
-    return AppConfig(
-        after_exception=[],
-        after_request=None,
-        after_response=None,
-        allowed_hosts=[],
-        before_request=None,
-        before_send=[],
-        response_cache_config=ResponseCacheConfig(),
-        cache_control=None,
-        compression_config=None,
-        cors_config=None,
-        csrf_config=None,
-        debug=False,
-        dependencies={},
-        etag=None,
-        event_emitter_backend=SimpleEventEmitter,
-        exception_handlers={},
-        guards=[],
-        listeners=[],
-        logging_config=None,
-        middleware=[],
-        multipart_form_part_limit=1000,
-        on_shutdown=[],
-        on_startup=[],
-        openapi_config=None,
-        opt={},
-        parameters={},
-        plugins=[],
-        request_class=None,
-        response_class=None,
-        response_cookies=[],
-        response_headers=[],
-        route_handlers=[],
-        security=[],
-        static_files_config=[],
-        tags=[],
-        template_config=None,
-        websocket_class=None,
-    )
-
-
-def test_app_params_defined_on_app_config_object() -> None:
-    """Ensures that all parameters to the `Litestar` constructor are present on the `AppConfig` object."""
-    litestar_signature = inspect.signature(Litestar)
-    app_config_fields = {f.name for f in fields(AppConfig)}
-    for name in litestar_signature.parameters:
-        if name in {"on_app_init", "initial_state", "_preferred_validation_backend"}:
-            continue
-        assert name in app_config_fields
-    # ensure there are not fields defined on AppConfig that aren't in the Litestar signature
-    assert not (app_config_fields - set(litestar_signature.parameters.keys()))
-
-
-def test_app_config_object_used(app_config_object: AppConfig, monkeypatch: pytest.MonkeyPatch) -> None:
-    """Ensure that the properties on the `AppConfig` object are accessed within the `Litestar` constructor.
-
-    In the test we replace every field on the `AppConfig` type with a property mock so that we can check that it has at
-    least been accessed. It doesn't actually check that we do the right thing with it, but is a guard against the case
-    of adding a parameter to the `Litestar` signature and to the `AppConfig` object, and using the value from the
-    parameter downstream from construction of the `AppConfig` object.
-    """
-
-    # replace each field on the `AppConfig` object with a `PropertyMock`, this allows us to assert that the properties
-    # have been accessed during app instantiation.
-    property_mocks: List[Tuple[str, Mock]] = []
-    for field in fields(AppConfig):
-        if field.name == "response_cache_config":
-            property_mock = PropertyMock(return_value=ResponseCacheConfig())
-        if field.name in ["event_emitter_backend", "response_cache_config"]:
-            property_mock = PropertyMock(return_value=Mock())
-        else:
-            # default iterable return value allows the mock properties that need to be iterated over in
-            # `Litestar.__init__()` to not blow up, for other properties it shouldn't matter what the value is for the
-            # sake of this test.
-            property_mock = PropertyMock(return_value=[])
-        property_mocks.append((field.name, property_mock))
-        monkeypatch.setattr(type(app_config_object), field.name, property_mock, raising=False)
-
-    # Things that we don't actually need to call for this test
-    monkeypatch.setattr(Litestar, "register", MagicMock())
-    monkeypatch.setattr(Litestar, "_create_asgi_handler", MagicMock())
-    monkeypatch.setattr(Router, "__init__", MagicMock())
-
-    # instantiates the app with an `on_app_config` that returns our patched `AppConfig` object.
-    Litestar(on_app_init=[MagicMock(return_value=app_config_object)])
-
-    # this ensures that each of the properties of the `AppConfig` object have been accessed within `Litestar.__init__()`
-    for name, mock in property_mocks:
-        assert mock.called, f"expected {name} to be called"
-
-
-def test_app_debug_create_logger() -> None:
-    app = Litestar([], debug=True)
-
-    assert app.logging_config
-    assert app.logging_config.loggers["litestar"]["level"] == "DEBUG"  # type: ignore[attr-defined]
-
-
-def test_app_debug_explicitly_disable_logging() -> None:
-    app = Litestar([], debug=True, logging_config=None)
-
-    assert not app.logging_config
-
-
-def test_app_debug_update_logging_config() -> None:
-    logging_config = LoggingConfig()
-    app = Litestar([], debug=True, logging_config=logging_config)
-
-    assert app.logging_config is logging_config
-    assert app.logging_config.loggers["litestar"]["level"] == "DEBUG"  # type: ignore[attr-defined]
-
-
-def test_set_state() -> None:
-    def modify_state_in_hook(app_config: AppConfig) -> AppConfig:
-        assert isinstance(app_config.state, State)
-        app_config.state["c"] = "D"
-        app_config.state["e"] = "f"
-        return app_config
-
-    app = Litestar(state=State({"a": "b", "c": "d"}), on_app_init=[modify_state_in_hook])
-    assert app.state._state == {"a": "b", "c": "D", "e": "f"}
-
-
-def test_app_from_config(app_config_object: AppConfig) -> None:
-    Litestar.from_config(app_config_object)
diff --git a/tests/app/test_before_send.py b/tests/app/test_before_send.py
deleted file mode 100644
--- a/tests/app/test_before_send.py
+++ /dev/null
@@ -1,33 +0,0 @@
-# ruff: noqa: UP006
-from __future__ import annotations
-
-from typing import TYPE_CHECKING
-
-from litestar import Litestar, get
-from litestar.datastructures import MutableScopeHeaders
-from litestar.status_codes import HTTP_200_OK
-from litestar.testing import create_test_client
-
-if TYPE_CHECKING:
-    from typing import Dict
-
-    from litestar.types import Message, Scope
-
-
-def test_before_send() -> None:
-    @get("/test")
-    def handler() -> Dict[str, str]:
-        return {"key": "value"}
-
-    async def before_send_hook_handler(message: Message, scope: Scope) -> None:
-        if message["type"] == "http.response.start":
-            headers = MutableScopeHeaders(message)
-            headers.add("My Header", scope["app"].state.message)
-
-    def on_startup(app: Litestar) -> None:
-        app.state.message = "value injected during send"
-
-    with create_test_client(handler, on_startup=[on_startup], before_send=[before_send_hook_handler]) as client:
-        response = client.get("/test")
-        assert response.status_code == HTTP_200_OK
-        assert response.headers.get("My Header") == "value injected during send"
diff --git a/tests/app/test_error_handling.py b/tests/app/test_error_handling.py
deleted file mode 100644
--- a/tests/app/test_error_handling.py
+++ /dev/null
@@ -1,68 +0,0 @@
-from litestar import Litestar, MediaType, Request, Response, get, post
-from litestar.exceptions import InternalServerException, NotFoundException
-from litestar.status_codes import HTTP_400_BAD_REQUEST, HTTP_500_INTERNAL_SERVER_ERROR
-from litestar.testing import TestClient, create_test_client
-from tests import Person
-
-
-def test_default_handling_of_pydantic_errors() -> None:
-    @post("/{param:int}")
-    def my_route_handler(param: int, data: Person) -> None:
-        ...
-
-    with create_test_client(my_route_handler) as client:
-        response = client.post("/123", json={"first_name": "moishe"})
-        extra = response.json().get("extra")
-        assert extra is not None
-        assert len(extra) == 3
-
-
-def test_using_custom_http_exception_handler() -> None:
-    @get("/{param:int}")
-    def my_route_handler(param: int) -> None:
-        ...
-
-    def my_custom_handler(_: Request, __: Exception) -> Response:
-        return Response(content="custom message", media_type=MediaType.TEXT, status_code=HTTP_400_BAD_REQUEST)
-
-    with create_test_client(my_route_handler, exception_handlers={NotFoundException: my_custom_handler}) as client:
-        response = client.get("/abc")
-        assert response.text == "custom message"
-        assert response.status_code == HTTP_400_BAD_REQUEST
-
-
-def test_debug_response_created() -> None:
-    # this will test exception causes are recorded in output
-    # since frames include code in context we should not raise
-    # exception directly
-    def exception_thrower() -> float:
-        return 1 / 0
-
-    @get("/")
-    def my_route_handler() -> None:
-        try:
-            exception_thrower()
-        except Exception as e:
-            raise InternalServerException() from e
-
-    app = Litestar(route_handlers=[my_route_handler], debug=True)
-    client = TestClient(app=app)
-
-    response = client.get("/")
-    assert response.status_code == HTTP_500_INTERNAL_SERVER_ERROR
-    assert "text/plain" in response.headers["content-type"]
-
-    response = client.get("/", headers={"accept": "text/html"})
-    assert response.status_code == HTTP_500_INTERNAL_SERVER_ERROR
-    assert "text/html" in response.headers["content-type"]
-    assert "ZeroDivisionError" in response.text
-
-
-def test_handler_error_return_status_500() -> None:
-    @get("/")
-    def my_route_handler() -> None:
-        raise KeyError("custom message")
-
-    with create_test_client(my_route_handler) as client:
-        response = client.get("/")
-        assert response.status_code == HTTP_500_INTERNAL_SERVER_ERROR
diff --git a/tests/app/test_lifespan.py b/tests/app/test_lifespan.py
deleted file mode 100644
--- a/tests/app/test_lifespan.py
+++ /dev/null
@@ -1,68 +0,0 @@
-from __future__ import annotations
-
-from typing import TYPE_CHECKING
-
-from litestar.datastructures import State
-from litestar.testing import create_test_client
-
-if TYPE_CHECKING:
-    from litestar import Litestar
-
-
-def test_lifespan() -> None:
-    events: list[str] = []
-    counter = {"value": 0}
-
-    def sync_function_without_app() -> None:
-        events.append("sync_function_without_app")
-        counter["value"] += 1
-
-    async def async_function_without_app() -> None:
-        events.append("async_function_without_app")
-        counter["value"] += 1
-
-    def sync_function_with_app(app: Litestar) -> None:
-        events.append("sync_function_with_app")
-        assert app is not None
-        assert isinstance(app.state, State)
-        counter["value"] += 1
-        app.state.x = True
-
-    async def async_function_with_app(app: Litestar) -> None:
-        events.append("async_function_with_app")
-        assert app is not None
-        assert isinstance(app.state, State)
-        counter["value"] += 1
-        app.state.y = True
-
-    with create_test_client(
-        [],
-        on_startup=[
-            sync_function_without_app,
-            async_function_without_app,
-            sync_function_with_app,
-            async_function_with_app,
-        ],
-        on_shutdown=[
-            sync_function_without_app,
-            async_function_without_app,
-            sync_function_with_app,
-            async_function_with_app,
-        ],
-    ) as client:
-        assert counter["value"] == 4
-        assert client.app.state.x
-        assert client.app.state.y
-        counter["value"] = 0
-        assert counter["value"] == 0
-    assert counter["value"] == 4
-    assert events == [
-        "sync_function_without_app",
-        "async_function_without_app",
-        "sync_function_with_app",
-        "async_function_with_app",
-        "sync_function_without_app",
-        "async_function_without_app",
-        "sync_function_with_app",
-        "async_function_with_app",
-    ]
diff --git a/tests/app/test_registering_route_handlers.py b/tests/app/test_registering_route_handlers.py
deleted file mode 100644
--- a/tests/app/test_registering_route_handlers.py
+++ /dev/null
@@ -1,19 +0,0 @@
-from litestar import Litestar, get
-
-
-def test_registering_route_handler_generates_openapi_docs() -> None:
-    def fn() -> None:
-        return
-
-    app = Litestar(route_handlers=[])
-    assert app.openapi_schema
-
-    app.register(get("/path1")(fn))
-
-    paths = app.openapi_schema.paths
-
-    assert paths is not None
-    assert paths.get("/path1")
-
-    app.register(get("/path2")(fn))
-    assert paths.get("/path2")
diff --git a/tests/asgi_router/routing_trie/test_path_param_resolution.py b/tests/asgi_router/routing_trie/test_path_param_resolution.py
deleted file mode 100644
--- a/tests/asgi_router/routing_trie/test_path_param_resolution.py
+++ /dev/null
@@ -1,21 +0,0 @@
-from litestar import get
-from litestar.status_codes import HTTP_200_OK, HTTP_404_NOT_FOUND
-from litestar.testing import create_test_client
-
-
-def test_root_path_param_resolution() -> None:
-    # https://github.com/litestar-org/litestar/issues/1830
-    @get("/{name:str}")
-    async def hello_world(name: str) -> str:
-        return f"Hello, {name}!"
-
-    with create_test_client(hello_world) as client:
-        response = client.get("/jon")
-        assert response.status_code == HTTP_200_OK
-        assert response.text == "Hello, jon!"
-
-        response = client.get("/jon/bon")
-        assert response.status_code == HTTP_404_NOT_FOUND
-
-        response = client.get("/jon/bon/jovi")
-        assert response.status_code == HTTP_404_NOT_FOUND
diff --git a/tests/asgi_router/test_adding_routes_to_trie.py b/tests/asgi_router/test_adding_routes_to_trie.py
deleted file mode 100644
--- a/tests/asgi_router/test_adding_routes_to_trie.py
+++ /dev/null
@@ -1,17 +0,0 @@
-from typing import TYPE_CHECKING
-
-import pytest
-
-from litestar import Litestar, asgi
-from litestar.exceptions import ImproperlyConfiguredException
-
-if TYPE_CHECKING:
-    from litestar.types import Receive, Scope, Send
-
-
-def test_add_mount_route_disallow_path_parameter() -> None:
-    async def handler(scope: "Scope", receive: "Receive", send: "Send") -> None:
-        return None
-
-    with pytest.raises(ImproperlyConfiguredException):
-        Litestar(route_handlers=[asgi("/mount-path", is_static=True)(handler), asgi("/mount-path/{id:str}")(handler)])
diff --git a/tests/conftest.py b/tests/conftest.py
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -1,70 +1,47 @@
 from __future__ import annotations
 
-import asyncio
 import importlib.util
 import logging
 import os
 import random
-import re
 import string
-import subprocess
 import sys
-import timeit
 from os import urandom
 from pathlib import Path
-from typing import (
-    TYPE_CHECKING,
-    Any,
-    Awaitable,
-    Callable,
-    Generator,
-    TypeVar,
-    Union,
-    cast,
-)
+from typing import TYPE_CHECKING, Any, AsyncGenerator, Callable, Generator, TypeVar, Union, cast
+from unittest.mock import AsyncMock, MagicMock
 
-import asyncmy
-import asyncpg
-import oracledb
 import pytest
-from _pytest.fixtures import FixtureRequest
 from fakeredis.aioredis import FakeRedis
 from freezegun import freeze_time
-from google.auth.credentials import AnonymousCredentials  # pyright: ignore
-from google.cloud import spanner  # pyright: ignore
-from oracledb.exceptions import DatabaseError, OperationalError
 from pytest_lazyfixture import lazy_fixture
 from redis.asyncio import Redis as AsyncRedis
-from redis.exceptions import ConnectionError as RedisConnectionError
+from redis.client import Redis
 
+from litestar.logging import LoggingConfig
+from litestar.logging.config import default_handlers as logging_default_handlers
 from litestar.middleware.session import SessionMiddleware
 from litestar.middleware.session.base import BaseSessionBackend
-from litestar.middleware.session.client_side import (
-    ClientSideSessionBackend,
-    CookieBackendConfig,
-)
-from litestar.middleware.session.server_side import (
-    ServerSideSessionBackend,
-    ServerSideSessionConfig,
-)
+from litestar.middleware.session.client_side import ClientSideSessionBackend, CookieBackendConfig
+from litestar.middleware.session.server_side import ServerSideSessionBackend, ServerSideSessionConfig
 from litestar.stores.base import Store
 from litestar.stores.file import FileStore
 from litestar.stores.memory import MemoryStore
 from litestar.stores.redis import RedisStore
 from litestar.testing import RequestFactory
-from litestar.utils.sync import AsyncCallable
 
 if TYPE_CHECKING:
     from types import ModuleType
 
     from freezegun.api import FrozenDateTimeFactory
-    from pytest import MonkeyPatch
+    from pytest import FixtureRequest, MonkeyPatch
 
     from litestar import Litestar
     from litestar.types import (
         AnyIOBackend,
         ASGIApp,
         ASGIVersion,
+        GetLogger,
         Receive,
         RouteHandlerType,
         Scope,
@@ -73,17 +50,20 @@
     )
 
 
+pytest_plugins = ["tests.docker_service_fixtures"]
+
+
+@pytest.fixture
+def mock() -> MagicMock:
+    return MagicMock()
+
+
 @pytest.fixture()
-def template_dir(tmp_path: Path) -> Path:
-    return tmp_path
+def async_mock() -> AsyncMock:
+    return AsyncMock()
 
 
-@pytest.fixture(
-    params=[
-        pytest.param("asyncio", id="asyncio"),
-        pytest.param("trio", id="trio"),
-    ]
-)
+@pytest.fixture(params=[pytest.param("asyncio", id="asyncio"), pytest.param("trio", id="trio")])
 def anyio_backend(request: pytest.FixtureRequest) -> str:
     return request.param  # type: ignore[no-any-return]
 
@@ -274,11 +254,6 @@ def module_name_generator() -> str:
     return wrapped
 
 
-@pytest.fixture(scope="module")
-def mock_db() -> MemoryStore:
-    return MemoryStore()
-
-
 @pytest.fixture()
 def frozen_datetime() -> Generator[FrozenDateTimeFactory, None, None]:
     with freeze_time() as frozen:
@@ -320,198 +295,27 @@ def enable_warn_implicit_sync_to_thread(monkeypatch: MonkeyPatch) -> None:
     monkeypatch.setenv("LITESTAR_WARN_IMPLICIT_SYNC_TO_THREAD", "1")
 
 
-# Docker services
-
-
-async def wait_until_responsive(
-    check: Callable[..., Awaitable],
-    timeout: float,
-    pause: float,
-    **kwargs: Any,
-) -> None:
-    """Wait until a service is responsive.
-
-    Args:
-        check: Coroutine, return truthy value when waiting should stop.
-        timeout: Maximum seconds to wait.
-        pause: Seconds to wait between calls to `check`.
-        **kwargs: Given as kwargs to `check`.
-    """
-    ref = timeit.default_timer()
-    now = ref
-    while (now - ref) < timeout:
-        if await check(**kwargs):
-            return
-        await asyncio.sleep(pause)
-        now = timeit.default_timer()
-
-    raise Exception("Timeout reached while waiting on service!")
-
-
-class DockerServiceRegistry:
-    def __init__(self) -> None:
-        self._running_services: set[str] = set()
-        self.docker_ip = self._get_docker_ip()
-        self._base_command = [
-            "docker-compose",
-            "--file=tests/docker-compose.yml",
-            "--project-name=litestar_pytest",
-        ]
-
-    def _get_docker_ip(self) -> str:
-        docker_host = os.environ.get("DOCKER_HOST", "").strip()
-        if not docker_host or docker_host.startswith("unix://"):
-            return "127.0.0.1"
-
-        match = re.match(r"^tcp://(.+?):\d+$", docker_host)
-        if not match:
-            raise ValueError(f'Invalid value for DOCKER_HOST: "{docker_host}".')
-        return match.group(1)
-
-    def run_command(self, *args: str) -> None:
-        subprocess.run([*self._base_command, *args], check=True, capture_output=True)
-
-    async def start(
-        self,
-        name: str,
-        *,
-        check: Callable[..., Awaitable],
-        timeout: float = 30,
-        pause: float = 0.1,
-        **kwargs: Any,
-    ) -> None:
-        if name not in self._running_services:
-            self.run_command("up", "-d", name)
-            self._running_services.add(name)
-
-            await wait_until_responsive(
-                check=AsyncCallable(check),
-                timeout=timeout,
-                pause=pause,
-                host=self.docker_ip,
-                **kwargs,
-            )
-
-    def stop(self, name: str) -> None:
-        pass
-
-    def down(self) -> None:
-        self.run_command("down", "-t", "5")
-
-
-@pytest.fixture(scope="session")
-def docker_services() -> Generator[DockerServiceRegistry, None, None]:
-    registry = DockerServiceRegistry()
-    yield registry
-    registry.down()
-
-
-@pytest.fixture(scope="session")
-def docker_ip(docker_services: DockerServiceRegistry) -> str:
-    return docker_services.docker_ip
-
-
-async def redis_responsive(host: str) -> bool:
-    client: AsyncRedis = AsyncRedis(host=host, port=6397)
-    try:
-        return await client.ping()
-    except (ConnectionError, RedisConnectionError):
-        return False
-    finally:
-        await client.close()
-
-
-@pytest.fixture()
-async def redis_service(docker_services: DockerServiceRegistry) -> None:
-    await docker_services.start("redis", check=redis_responsive)
-
-
-async def mysql_responsive(host: str) -> bool:
-    try:
-        conn = await asyncmy.connect(
-            host=host,
-            port=3360,
-            user="app",
-            database="db",
-            password="super-secret",
-        )
-        async with conn.cursor() as cursor:
-            await cursor.execute("select 1 as is_available")
-            resp = await cursor.fetchone()
-        return bool(resp[0] == 1)
-    except asyncmy.errors.OperationalError:  # pyright: ignore
-        return False
-
-
-@pytest.fixture()
-async def mysql_service(docker_services: DockerServiceRegistry) -> None:
-    await docker_services.start("mysql", check=mysql_responsive)
-
-
-async def postgres_responsive(host: str) -> bool:
-    try:
-        conn = await asyncpg.connect(
-            host=host, port=5423, user="postgres", database="postgres", password="super-secret"
-        )
-    except (ConnectionError, asyncpg.CannotConnectNowError):
-        return False
-
-    try:
-        return (await conn.fetchrow("SELECT 1"))[0] == 1  # type: ignore
-    finally:
-        await conn.close()
+@pytest.fixture
+def get_logger() -> GetLogger:
+    # due to the limitations of caplog we have to place this call here.
+    # we also have to allow propagation.
+    return LoggingConfig(
+        handlers=logging_default_handlers,
+        loggers={
+            "litestar": {"level": "INFO", "handlers": ["queue_listener"], "propagate": True},
+        },
+    ).configure()
 
 
 @pytest.fixture()
-async def postgres_service(docker_services: DockerServiceRegistry) -> None:
-    await docker_services.start("postgres", check=postgres_responsive)
-
+async def redis_client(docker_ip: str, redis_service: None) -> AsyncGenerator[AsyncRedis, None]:
+    # this is to get around some weirdness with pytest-asyncio and redis interaction
+    # on 3.8 and 3.9
 
-def oracle_responsive(host: str) -> bool:
+    Redis(host=docker_ip, port=6397).flushall()
+    client: AsyncRedis = AsyncRedis(host=docker_ip, port=6397)
+    yield client
     try:
-        conn = oracledb.connect(
-            host=host,
-            port=1512,
-            user="app",
-            service_name="xepdb1",
-            password="super-secret",
-        )
-        with conn.cursor() as cursor:
-            cursor.execute("SELECT 1 FROM dual")
-            resp = cursor.fetchone()
-        return bool(resp[0] == 1)
-    except (OperationalError, DatabaseError):  # pyright: ignore
-        return False
-
-
-@pytest.fixture()
-async def oracle_service(docker_services: DockerServiceRegistry) -> None:
-    await docker_services.start("oracle", check=AsyncCallable(oracle_responsive), timeout=60)
-
-
-def spanner_responsive(host: str) -> bool:
-    try:
-        os.environ["SPANNER_EMULATOR_HOST"] = "localhost:9010"
-        os.environ["GOOGLE_CLOUD_PROJECT"] = "emulator-test-project"
-        spanner_client = spanner.Client(project="emulator-test-project", credentials=AnonymousCredentials())
-        instance = spanner_client.instance("test-instance")
-        try:
-            instance.create()
-        except Exception:  # pyright: ignore
-            pass
-        database = instance.database("test-database")
-        try:
-            database.create()
-        except Exception:  # pyright: ignore
-            pass
-        with database.snapshot() as snapshot:
-            resp = list(snapshot.execute_sql("SELECT 1"))[0]
-        return bool(resp[0] == 1)
-    except Exception:  # pyright: ignore
-        return False
-
-
-@pytest.fixture()
-async def spanner_service(docker_services: DockerServiceRegistry) -> None:
-    os.environ["SPANNER_EMULATOR_HOST"] = "localhost:9010"
-    await docker_services.start("spanner", timeout=60, check=AsyncCallable(spanner_responsive))
+        await client.close()
+    except RuntimeError:
+        pass
diff --git a/tests/connection/request/test_request_state.py b/tests/connection/request/test_request_state.py
deleted file mode 100644
--- a/tests/connection/request/test_request_state.py
+++ /dev/null
@@ -1,34 +0,0 @@
-from typing import TYPE_CHECKING, Dict
-
-from litestar import Request, get
-from litestar.middleware import MiddlewareProtocol
-from litestar.testing import create_test_client
-
-if TYPE_CHECKING:
-    from litestar.types import ASGIApp, Receive, Scope, Send
-
-
-class BeforeRequestMiddleWare(MiddlewareProtocol):
-    def __init__(self, app: "ASGIApp") -> None:
-        self.app = app
-
-    async def __call__(self, scope: "Scope", receive: "Receive", send: "Send") -> None:
-        scope["state"]["main"] = 1
-        await self.app(scope, receive, send)
-
-
-def before_request(request: Request) -> None:
-    assert request.state.main == 1
-    request.state.main = 2
-
-
-def test_state() -> None:
-    @get(path="/")
-    async def get_state(request: Request) -> Dict[str, str]:
-        return {"state": request.state.main}
-
-    with create_test_client(
-        route_handlers=[get_state], middleware=[BeforeRequestMiddleWare], before_request=before_request
-    ) as client:
-        response = client.get("/")
-        assert response.json() == {"state": 2}
diff --git a/tests/contrib/sqlalchemy/conftest.py b/tests/contrib/sqlalchemy/conftest.py
deleted file mode 100644
--- a/tests/contrib/sqlalchemy/conftest.py
+++ /dev/null
@@ -1,9 +0,0 @@
-from __future__ import annotations
-
-try:
-    import sqlalchemy
-
-    if sqlalchemy.__version__.startswith("1."):
-        collect_ignore_glob = ["*"]
-except ImportError:
-    collect_ignore_glob = ["*"]
diff --git a/tests/dependency_injection/test_dependency_validation.py b/tests/dependency_injection/test_dependency_validation.py
deleted file mode 100644
--- a/tests/dependency_injection/test_dependency_validation.py
+++ /dev/null
@@ -1,38 +0,0 @@
-import pytest
-
-from litestar import Litestar, get
-from litestar.di import Provide
-from litestar.exceptions import ImproperlyConfiguredException
-
-
-async def first_method(query_param: int) -> int:
-    assert isinstance(query_param, int)
-    return query_param
-
-
-async def second_method(path_param: str) -> str:
-    assert isinstance(path_param, str)
-    return path_param
-
-
-def test_dependency_validation() -> None:
-    @get(
-        path="/{path_param:int}",
-        dependencies={
-            "first": Provide(first_method),
-            "second": Provide(second_method),
-        },
-    )
-    def test_function(first: int, second: str, third: int) -> None:
-        pass
-
-    with pytest.raises(ImproperlyConfiguredException):
-        Litestar(
-            route_handlers=[test_function],
-            dependencies={"third": Provide(first_method)},
-        )
-
-
-def test_raises_when_dependency_is_not_callable() -> None:
-    with pytest.raises(ImproperlyConfiguredException):
-        Provide(123)  # type: ignore
diff --git a/tests/docker_service_fixtures.py b/tests/docker_service_fixtures.py
new file mode 100644
--- /dev/null
+++ b/tests/docker_service_fixtures.py
@@ -0,0 +1,220 @@
+from __future__ import annotations
+
+import asyncio
+import os
+import re
+import subprocess
+import sys
+import timeit
+from typing import Any, Awaitable, Callable, Generator
+
+import asyncmy
+import asyncpg
+import oracledb
+import pytest
+from google.auth.credentials import AnonymousCredentials  # pyright: ignore
+from google.cloud import spanner  # pyright: ignore
+from oracledb import DatabaseError, OperationalError
+from redis.asyncio import Redis as AsyncRedis
+from redis.exceptions import ConnectionError as RedisConnectionError
+
+from litestar.utils import AsyncCallable
+
+
+async def wait_until_responsive(
+    check: Callable[..., Awaitable],
+    timeout: float,
+    pause: float,
+    **kwargs: Any,
+) -> None:
+    """Wait until a service is responsive.
+
+    Args:
+        check: Coroutine, return truthy value when waiting should stop.
+        timeout: Maximum seconds to wait.
+        pause: Seconds to wait between calls to `check`.
+        **kwargs: Given as kwargs to `check`.
+    """
+    ref = timeit.default_timer()
+    now = ref
+    while (now - ref) < timeout:
+        if await check(**kwargs):
+            return
+        await asyncio.sleep(pause)
+        now = timeit.default_timer()
+
+    raise Exception("Timeout reached while waiting on service!")
+
+
+class DockerServiceRegistry:
+    def __init__(self) -> None:
+        self._running_services: set[str] = set()
+        self.docker_ip = self._get_docker_ip()
+        self._base_command = [
+            "docker-compose",
+            "--file=tests/docker-compose.yml",
+            "--project-name=litestar_pytest",
+        ]
+
+    def _get_docker_ip(self) -> str:
+        docker_host = os.environ.get("DOCKER_HOST", "").strip()
+        if not docker_host or docker_host.startswith("unix://"):
+            return "127.0.0.1"
+
+        match = re.match(r"^tcp://(.+?):\d+$", docker_host)
+        if not match:
+            raise ValueError(f'Invalid value for DOCKER_HOST: "{docker_host}".')
+        return match.group(1)
+
+    def run_command(self, *args: str) -> None:
+        subprocess.run([*self._base_command, *args], check=True, capture_output=True)
+
+    async def start(
+        self,
+        name: str,
+        *,
+        check: Callable[..., Awaitable],
+        timeout: float = 30,
+        pause: float = 0.1,
+        **kwargs: Any,
+    ) -> None:
+        if name not in self._running_services:
+            self.run_command("up", "-d", name)
+            self._running_services.add(name)
+
+            await wait_until_responsive(
+                check=AsyncCallable(check),
+                timeout=timeout,
+                pause=pause,
+                host=self.docker_ip,
+                **kwargs,
+            )
+
+    def stop(self, name: str) -> None:
+        pass
+
+    def down(self) -> None:
+        self.run_command("down", "-t", "5")
+
+
+@pytest.fixture(scope="session")
+def docker_services() -> Generator[DockerServiceRegistry, None, None]:
+    if sys.platform != "linux":
+        pytest.skip("Docker not available on this platform")
+
+    registry = DockerServiceRegistry()
+    try:
+        yield registry
+    finally:
+        registry.down()
+
+
+@pytest.fixture(scope="session")
+def docker_ip(docker_services: DockerServiceRegistry) -> str:
+    return docker_services.docker_ip
+
+
+async def redis_responsive(host: str) -> bool:
+    client: AsyncRedis = AsyncRedis(host=host, port=6397)
+    try:
+        return await client.ping()
+    except (ConnectionError, RedisConnectionError):
+        return False
+    finally:
+        await client.close()
+
+
+@pytest.fixture()
+async def redis_service(docker_services: DockerServiceRegistry) -> None:
+    await docker_services.start("redis", check=redis_responsive)
+
+
+async def mysql_responsive(host: str) -> bool:
+    try:
+        conn = await asyncmy.connect(
+            host=host,
+            port=3360,
+            user="app",
+            database="db",
+            password="super-secret",
+        )
+        async with conn.cursor() as cursor:
+            await cursor.execute("select 1 as is_available")
+            resp = await cursor.fetchone()
+        return bool(resp[0] == 1)
+    except asyncmy.errors.OperationalError:  # pyright: ignore
+        return False
+
+
+@pytest.fixture()
+async def mysql_service(docker_services: DockerServiceRegistry) -> None:
+    await docker_services.start("mysql", check=mysql_responsive)
+
+
+async def postgres_responsive(host: str) -> bool:
+    try:
+        conn = await asyncpg.connect(
+            host=host, port=5423, user="postgres", database="postgres", password="super-secret"
+        )
+    except (ConnectionError, asyncpg.CannotConnectNowError):
+        return False
+
+    try:
+        return (await conn.fetchrow("SELECT 1"))[0] == 1  # type: ignore
+    finally:
+        await conn.close()
+
+
+@pytest.fixture()
+async def postgres_service(docker_services: DockerServiceRegistry) -> None:
+    await docker_services.start("postgres", check=postgres_responsive)
+
+
+def oracle_responsive(host: str) -> bool:
+    try:
+        conn = oracledb.connect(
+            host=host,
+            port=1512,
+            user="app",
+            service_name="xepdb1",
+            password="super-secret",
+        )
+        with conn.cursor() as cursor:
+            cursor.execute("SELECT 1 FROM dual")
+            resp = cursor.fetchone()
+        return bool(resp[0] == 1)
+    except (OperationalError, DatabaseError):  # pyright: ignore
+        return False
+
+
+@pytest.fixture()
+async def oracle_service(docker_services: DockerServiceRegistry) -> None:
+    await docker_services.start("oracle", check=AsyncCallable(oracle_responsive), timeout=60)
+
+
+def spanner_responsive(host: str) -> bool:
+    try:
+        os.environ["SPANNER_EMULATOR_HOST"] = "localhost:9010"
+        os.environ["GOOGLE_CLOUD_PROJECT"] = "emulator-test-project"
+        spanner_client = spanner.Client(project="emulator-test-project", credentials=AnonymousCredentials())
+        instance = spanner_client.instance("test-instance")
+        try:
+            instance.create()
+        except Exception:  # pyright: ignore
+            pass
+        database = instance.database("test-database")
+        try:
+            database.create()
+        except Exception:  # pyright: ignore
+            pass
+        with database.snapshot() as snapshot:
+            resp = list(snapshot.execute_sql("SELECT 1"))[0]
+        return bool(resp[0] == 1)
+    except Exception:  # pyright: ignore
+        return False
+
+
+@pytest.fixture()
+async def spanner_service(docker_services: DockerServiceRegistry) -> None:
+    os.environ["SPANNER_EMULATOR_HOST"] = "localhost:9010"
+    await docker_services.start("spanner", timeout=60, check=AsyncCallable(spanner_responsive))
diff --git a/docs/examples/tests/__init__.py b/tests/e2e/__init__.py
similarity index 100%
rename from docs/examples/tests/__init__.py
rename to tests/e2e/__init__.py
diff --git a/docs/examples/tests/application_hooks/__init__.py b/tests/e2e/test_dependency_injection/__init__.py
similarity index 100%
rename from docs/examples/tests/application_hooks/__init__.py
rename to tests/e2e/test_dependency_injection/__init__.py
diff --git a/tests/e2e/test_dependency_injection/test_dependency_validation.py b/tests/e2e/test_dependency_injection/test_dependency_validation.py
new file mode 100644
--- /dev/null
+++ b/tests/e2e/test_dependency_injection/test_dependency_validation.py
@@ -0,0 +1,24 @@
+import pytest
+
+from litestar import Litestar, get
+from litestar.exceptions import ImproperlyConfiguredException
+
+
+async def first_method(query_param: int) -> int:
+    return query_param
+
+
+async def second_method(path_param: str) -> str:
+    return path_param
+
+
+def test_dependency_validation() -> None:
+    @get(
+        path="/{path_param:int}",
+        dependencies={"first": first_method, "second": second_method},
+    )
+    def handler(first: int, second: str, third: int) -> None:
+        pass
+
+    with pytest.raises(ImproperlyConfiguredException):
+        Litestar(route_handlers=[handler], dependencies={"third": first_method})
diff --git a/tests/dependency_injection/test_http_handler_dependency_injection.py b/tests/e2e/test_dependency_injection/test_http_handler_dependency_injection.py
similarity index 100%
rename from tests/dependency_injection/test_http_handler_dependency_injection.py
rename to tests/e2e/test_dependency_injection/test_http_handler_dependency_injection.py
diff --git a/tests/dependency_injection/test_injection_of_classes.py b/tests/e2e/test_dependency_injection/test_injection_of_classes.py
similarity index 100%
rename from tests/dependency_injection/test_injection_of_classes.py
rename to tests/e2e/test_dependency_injection/test_injection_of_classes.py
diff --git a/tests/dependency_injection/test_injection_of_generic_models.py b/tests/e2e/test_dependency_injection/test_injection_of_generic_models.py
similarity index 100%
rename from tests/dependency_injection/test_injection_of_generic_models.py
rename to tests/e2e/test_dependency_injection/test_injection_of_generic_models.py
diff --git a/tests/dependency_injection/test_inter_dependencies.py b/tests/e2e/test_dependency_injection/test_inter_dependencies.py
similarity index 100%
rename from tests/dependency_injection/test_inter_dependencies.py
rename to tests/e2e/test_dependency_injection/test_inter_dependencies.py
diff --git a/tests/dependency_injection/test_request_local_caching.py b/tests/e2e/test_dependency_injection/test_request_local_caching.py
similarity index 100%
rename from tests/dependency_injection/test_request_local_caching.py
rename to tests/e2e/test_dependency_injection/test_request_local_caching.py
diff --git a/tests/dependency_injection/test_websocket_handler_dependency_injection.py b/tests/e2e/test_dependency_injection/test_websocket_handler_dependency_injection.py
similarity index 100%
rename from tests/dependency_injection/test_websocket_handler_dependency_injection.py
rename to tests/e2e/test_dependency_injection/test_websocket_handler_dependency_injection.py
diff --git a/tests/test_exception_handlers.py b/tests/e2e/test_exception_handlers.py
similarity index 100%
rename from tests/test_exception_handlers.py
rename to tests/e2e/test_exception_handlers.py
diff --git a/docs/examples/tests/application_state/__init__.py b/tests/e2e/test_life_cycle_hooks/__init__.py
similarity index 100%
rename from docs/examples/tests/application_state/__init__.py
rename to tests/e2e/test_life_cycle_hooks/__init__.py
diff --git a/tests/life_cycle_hooks/test_after_request.py b/tests/e2e/test_life_cycle_hooks/test_after_request.py
similarity index 100%
rename from tests/life_cycle_hooks/test_after_request.py
rename to tests/e2e/test_life_cycle_hooks/test_after_request.py
diff --git a/tests/life_cycle_hooks/test_after_response.py b/tests/e2e/test_life_cycle_hooks/test_after_response.py
similarity index 100%
rename from tests/life_cycle_hooks/test_after_response.py
rename to tests/e2e/test_life_cycle_hooks/test_after_response.py
diff --git a/tests/life_cycle_hooks/test_before_request.py b/tests/e2e/test_life_cycle_hooks/test_before_request.py
similarity index 100%
rename from tests/life_cycle_hooks/test_before_request.py
rename to tests/e2e/test_life_cycle_hooks/test_before_request.py
diff --git a/tests/test_option_requests.py b/tests/e2e/test_option_requests.py
similarity index 100%
rename from tests/test_option_requests.py
rename to tests/e2e/test_option_requests.py
diff --git a/tests/test_response_caching.py b/tests/e2e/test_response_caching.py
similarity index 100%
rename from tests/test_response_caching.py
rename to tests/e2e/test_response_caching.py
diff --git a/tests/test_router_registration.py b/tests/e2e/test_router_registration.py
similarity index 100%
rename from tests/test_router_registration.py
rename to tests/e2e/test_router_registration.py
diff --git a/docs/examples/tests/contrib/__init__.py b/tests/e2e/test_routing/__init__.py
similarity index 100%
rename from docs/examples/tests/contrib/__init__.py
rename to tests/e2e/test_routing/__init__.py
diff --git a/tests/routing/test_asset_url_path.py b/tests/e2e/test_routing/test_asset_url_path.py
similarity index 100%
rename from tests/routing/test_asset_url_path.py
rename to tests/e2e/test_routing/test_asset_url_path.py
diff --git a/tests/routing/test_path_mounting.py b/tests/e2e/test_routing/test_path_mounting.py
similarity index 100%
rename from tests/routing/test_path_mounting.py
rename to tests/e2e/test_routing/test_path_mounting.py
diff --git a/tests/routing/test_path_resolution.py b/tests/e2e/test_routing/test_path_resolution.py
similarity index 93%
rename from tests/routing/test_path_resolution.py
rename to tests/e2e/test_routing/test_path_resolution.py
--- a/tests/routing/test_path_resolution.py
+++ b/tests/e2e/test_routing/test_path_resolution.py
@@ -255,3 +255,21 @@ def upper_handler(string_param: str, parth_param: Path) -> str:
 
         response = client.get("/abc/a/b/c")
         assert response.status_code == HTTP_200_OK
+
+
+def test_root_path_param_resolution() -> None:
+    # https://github.com/litestar-org/litestar/issues/1830
+    @get("/{name:str}")
+    async def hello_world(name: str) -> str:
+        return f"Hello, {name}!"
+
+    with create_test_client(hello_world) as client:
+        response = client.get("/jon")
+        assert response.status_code == HTTP_200_OK
+        assert response.text == "Hello, jon!"
+
+        response = client.get("/jon/bon")
+        assert response.status_code == HTTP_404_NOT_FOUND
+
+        response = client.get("/jon/bon/jovi")
+        assert response.status_code == HTTP_404_NOT_FOUND
diff --git a/tests/routing/test_route_indexing.py b/tests/e2e/test_routing/test_route_indexing.py
similarity index 100%
rename from tests/routing/test_route_indexing.py
rename to tests/e2e/test_routing/test_route_indexing.py
diff --git a/tests/routing/test_route_reverse.py b/tests/e2e/test_routing/test_route_reverse.py
similarity index 100%
rename from tests/routing/test_route_reverse.py
rename to tests/e2e/test_routing/test_route_reverse.py
diff --git a/tests/routing/test_validations.py b/tests/e2e/test_routing/test_validations.py
similarity index 100%
rename from tests/routing/test_validations.py
rename to tests/e2e/test_routing/test_validations.py
diff --git a/tests/compatibility/test_starlette_responses.py b/tests/e2e/test_starlette_responses.py
similarity index 100%
rename from tests/compatibility/test_starlette_responses.py
rename to tests/e2e/test_starlette_responses.py
diff --git a/docs/examples/tests/contrib/jwt/__init__.py b/tests/examples/__init__.py
similarity index 100%
rename from docs/examples/tests/contrib/jwt/__init__.py
rename to tests/examples/__init__.py
diff --git a/tests/examples/conftest.py b/tests/examples/conftest.py
new file mode 100644
--- /dev/null
+++ b/tests/examples/conftest.py
@@ -0,0 +1,14 @@
+import logging
+from typing import Generator
+
+import pytest
+
+
+@pytest.fixture(autouse=True)
+def disable_httpx_logging() -> Generator[None, None, None]:
+    # ensure that httpx logging is not interfering with our test client
+    httpx_logger = logging.getLogger("httpx")
+    initial_level = httpx_logger.level
+    httpx_logger.setLevel(logging.WARNING)
+    yield
+    httpx_logger.setLevel(initial_level)
diff --git a/docs/examples/tests/contrib/sqlalchemy/__init__.py b/tests/examples/test_application_hooks/__init__.py
similarity index 100%
rename from docs/examples/tests/contrib/sqlalchemy/__init__.py
rename to tests/examples/test_application_hooks/__init__.py
diff --git a/docs/examples/tests/application_hooks/test_application_after_exception_hook.py b/tests/examples/test_application_hooks/test_application_after_exception_hook.py
similarity index 91%
rename from docs/examples/tests/application_hooks/test_application_after_exception_hook.py
rename to tests/examples/test_application_hooks/test_application_after_exception_hook.py
--- a/docs/examples/tests/application_hooks/test_application_after_exception_hook.py
+++ b/tests/examples/test_application_hooks/test_application_after_exception_hook.py
@@ -2,8 +2,8 @@
 from typing import TYPE_CHECKING
 
 import pytest
+from docs.examples.application_hooks import after_exception_hook
 
-from examples.application_hooks import after_exception_hook
 from litestar.testing import TestClient
 
 if TYPE_CHECKING:
diff --git a/docs/examples/tests/application_hooks/test_application_before_send.py b/tests/examples/test_application_hooks/test_application_before_send.py
similarity index 85%
rename from docs/examples/tests/application_hooks/test_application_before_send.py
rename to tests/examples/test_application_hooks/test_application_before_send.py
--- a/docs/examples/tests/application_hooks/test_application_before_send.py
+++ b/tests/examples/test_application_hooks/test_application_before_send.py
@@ -1,4 +1,5 @@
-from examples.application_hooks import before_send_hook
+from docs.examples.application_hooks import before_send_hook
+
 from litestar.status_codes import HTTP_200_OK
 from litestar.testing import TestClient
 
diff --git a/docs/examples/tests/application_hooks/test_lifespan_manager.py b/tests/examples/test_application_hooks/test_lifespan_manager.py
similarity index 78%
rename from docs/examples/tests/application_hooks/test_lifespan_manager.py
rename to tests/examples/test_application_hooks/test_lifespan_manager.py
--- a/docs/examples/tests/application_hooks/test_lifespan_manager.py
+++ b/tests/examples/test_application_hooks/test_lifespan_manager.py
@@ -1,8 +1,8 @@
 from unittest.mock import AsyncMock
 
+from docs.examples.application_hooks.lifespan_manager import app
 from pytest_mock import MockerFixture
 
-from examples.application_hooks.lifespan_manager import app
 from litestar import get
 from litestar.datastructures import State
 from litestar.testing import TestClient
@@ -13,7 +13,7 @@ class FakeAsyncEngine:
 
 
 async def test_startup_and_shutdown_example(mocker: MockerFixture) -> None:
-    mock_create_engine = mocker.patch("examples.application_hooks.lifespan_manager.create_async_engine")
+    mock_create_engine = mocker.patch("docs.examples.application_hooks.lifespan_manager.create_async_engine")
     mock_create_engine.return_value = FakeAsyncEngine
 
     @get("/")
diff --git a/docs/examples/tests/application_hooks/test_on_app_init.py b/tests/examples/test_application_hooks/test_on_app_init.py
similarity index 50%
rename from docs/examples/tests/application_hooks/test_on_app_init.py
rename to tests/examples/test_application_hooks/test_on_app_init.py
--- a/docs/examples/tests/application_hooks/test_on_app_init.py
+++ b/tests/examples/test_application_hooks/test_on_app_init.py
@@ -1,4 +1,4 @@
-from examples.application_hooks.on_app_init import app, close_db_connection
+from docs.examples.application_hooks.on_app_init import app, close_db_connection
 
 
 def test_on_app_init() -> None:
diff --git a/docs/examples/tests/contrib/sqlalchemy/plugins/__init__.py b/tests/examples/test_application_state/__init__.py
similarity index 100%
rename from docs/examples/tests/contrib/sqlalchemy/plugins/__init__.py
rename to tests/examples/test_application_state/__init__.py
diff --git a/docs/examples/tests/application_state/test_passing_initial_state.py b/tests/examples/test_application_state/test_passing_initial_state.py
similarity index 81%
rename from docs/examples/tests/application_state/test_passing_initial_state.py
rename to tests/examples/test_application_state/test_passing_initial_state.py
--- a/docs/examples/tests/application_state/test_passing_initial_state.py
+++ b/tests/examples/test_application_state/test_passing_initial_state.py
@@ -1,4 +1,5 @@
-from examples.application_state.passing_initial_state import app
+from docs.examples.application_state.passing_initial_state import app
+
 from litestar.status_codes import HTTP_200_OK
 from litestar.testing import TestClient
 
diff --git a/docs/examples/tests/application_state/test_using_application_state.py b/tests/examples/test_application_state/test_using_application_state.py
similarity index 74%
rename from docs/examples/tests/application_state/test_using_application_state.py
rename to tests/examples/test_application_state/test_using_application_state.py
--- a/docs/examples/tests/application_state/test_using_application_state.py
+++ b/tests/examples/test_application_state/test_using_application_state.py
@@ -2,15 +2,17 @@
 from typing import Any
 
 import pytest
+from docs.examples.application_state.using_application_state import app
 
-from examples.application_state.using_application_state import app
 from litestar.status_codes import HTTP_200_OK
 from litestar.testing import TestClient
 
 
 @pytest.mark.usefixtures("reset_httpx_logging")
 def test_using_application_state(caplog: Any) -> None:
-    with caplog.at_level(INFO, "examples.application_state.using_application_state"), TestClient(app=app) as client:
+    with caplog.at_level(INFO, "docs.examples.application_state.using_application_state"), TestClient(
+        app=app
+    ) as client:
         response = client.get("/")
         assert response.status_code == HTTP_200_OK
 
diff --git a/docs/examples/tests/application_state/test_using_custom_state.py b/tests/examples/test_application_state/test_using_custom_state.py
similarity index 81%
rename from docs/examples/tests/application_state/test_using_custom_state.py
rename to tests/examples/test_application_state/test_using_custom_state.py
--- a/docs/examples/tests/application_state/test_using_custom_state.py
+++ b/tests/examples/test_application_state/test_using_custom_state.py
@@ -1,4 +1,5 @@
-from examples.application_state.using_custom_state import app
+from docs.examples.application_state.using_custom_state import app
+
 from litestar.status_codes import HTTP_200_OK
 from litestar.testing import TestClient
 
diff --git a/docs/examples/tests/application_state/test_using_immutable_state.py b/tests/examples/test_application_state/test_using_immutable_state.py
similarity index 80%
rename from docs/examples/tests/application_state/test_using_immutable_state.py
rename to tests/examples/test_application_state/test_using_immutable_state.py
--- a/docs/examples/tests/application_state/test_using_immutable_state.py
+++ b/tests/examples/test_application_state/test_using_immutable_state.py
@@ -1,4 +1,5 @@
-from examples.application_state.using_immutable_state import app
+from docs.examples.application_state.using_immutable_state import app
+
 from litestar.status_codes import HTTP_500_INTERNAL_SERVER_ERROR
 from litestar.testing import TestClient
 
diff --git a/docs/examples/tests/datastructures/headers/test_cache_control.py b/tests/examples/test_cache_control_headers.py
similarity index 89%
rename from docs/examples/tests/datastructures/headers/test_cache_control.py
rename to tests/examples/test_cache_control_headers.py
--- a/docs/examples/tests/datastructures/headers/test_cache_control.py
+++ b/tests/examples/test_cache_control_headers.py
@@ -1,4 +1,5 @@
-from examples.datastructures.headers import cache_control
+from docs.examples.datastructures.headers import cache_control
+
 from litestar.testing import TestClient
 
 
diff --git a/docs/examples/tests/data_transfer_objects/__init__.py b/tests/examples/test_contrib/__init__.py
similarity index 100%
rename from docs/examples/tests/data_transfer_objects/__init__.py
rename to tests/examples/test_contrib/__init__.py
diff --git a/docs/examples/tests/data_transfer_objects/factory/__init__.py b/tests/examples/test_contrib/test_jwt/__init__.py
similarity index 100%
rename from docs/examples/tests/data_transfer_objects/factory/__init__.py
rename to tests/examples/test_contrib/test_jwt/__init__.py
diff --git a/docs/examples/tests/contrib/jwt/test_using_jwt_auth.py b/tests/examples/test_contrib/test_jwt/test_using_jwt_auth.py
similarity index 92%
rename from docs/examples/tests/contrib/jwt/test_using_jwt_auth.py
rename to tests/examples/test_contrib/test_jwt/test_using_jwt_auth.py
--- a/docs/examples/tests/contrib/jwt/test_using_jwt_auth.py
+++ b/tests/examples/test_contrib/test_jwt/test_using_jwt_auth.py
@@ -1,6 +1,7 @@
 from uuid import uuid4
 
-from examples.contrib.jwt.using_jwt_auth import app
+from docs.examples.contrib.jwt.using_jwt_auth import app
+
 from litestar.status_codes import HTTP_200_OK, HTTP_201_CREATED, HTTP_401_UNAUTHORIZED
 from litestar.testing import TestClient
 
diff --git a/docs/examples/tests/contrib/jwt/test_using_jwt_cookie_auth.py b/tests/examples/test_contrib/test_jwt/test_using_jwt_cookie_auth.py
similarity index 90%
rename from docs/examples/tests/contrib/jwt/test_using_jwt_cookie_auth.py
rename to tests/examples/test_contrib/test_jwt/test_using_jwt_cookie_auth.py
--- a/docs/examples/tests/contrib/jwt/test_using_jwt_cookie_auth.py
+++ b/tests/examples/test_contrib/test_jwt/test_using_jwt_cookie_auth.py
@@ -1,6 +1,7 @@
 from uuid import uuid4
 
-from examples.contrib.jwt.using_jwt_cookie_auth import app
+from docs.examples.contrib.jwt.using_jwt_cookie_auth import app
+
 from litestar.status_codes import HTTP_200_OK, HTTP_201_CREATED, HTTP_401_UNAUTHORIZED
 from litestar.testing import TestClient
 
diff --git a/docs/examples/tests/contrib/jwt/test_using_oauth2_password_bearer.py b/tests/examples/test_contrib/test_jwt/test_using_oauth2_password_bearer.py
similarity index 88%
rename from docs/examples/tests/contrib/jwt/test_using_oauth2_password_bearer.py
rename to tests/examples/test_contrib/test_jwt/test_using_oauth2_password_bearer.py
--- a/docs/examples/tests/contrib/jwt/test_using_oauth2_password_bearer.py
+++ b/tests/examples/test_contrib/test_jwt/test_using_oauth2_password_bearer.py
@@ -1,6 +1,7 @@
 from uuid import uuid4
 
-from examples.contrib.jwt.using_oauth2_password_bearer import app
+from docs.examples.contrib.jwt.using_oauth2_password_bearer import app
+
 from litestar.status_codes import HTTP_201_CREATED, HTTP_401_UNAUTHORIZED
 from litestar.testing import TestClient
 
diff --git a/docs/examples/tests/datastructures/__init__.py b/tests/examples/test_contrib/test_sqlalchemy/__init__.py
similarity index 100%
rename from docs/examples/tests/datastructures/__init__.py
rename to tests/examples/test_contrib/test_sqlalchemy/__init__.py
diff --git a/docs/examples/tests/datastructures/headers/__init__.py b/tests/examples/test_contrib/test_sqlalchemy/plugins/__init__.py
similarity index 100%
rename from docs/examples/tests/datastructures/headers/__init__.py
rename to tests/examples/test_contrib/test_sqlalchemy/plugins/__init__.py
diff --git a/docs/examples/tests/contrib/sqlalchemy/plugins/test_example_apps.py b/tests/examples/test_contrib/test_sqlalchemy/plugins/test_example_apps.py
similarity index 100%
rename from docs/examples/tests/contrib/sqlalchemy/plugins/test_example_apps.py
rename to tests/examples/test_contrib/test_sqlalchemy/plugins/test_example_apps.py
diff --git a/docs/examples/tests/contrib/sqlalchemy/plugins/test_tutorial_example_apps.py b/tests/examples/test_contrib/test_sqlalchemy/plugins/test_tutorial_example_apps.py
similarity index 100%
rename from docs/examples/tests/contrib/sqlalchemy/plugins/test_tutorial_example_apps.py
rename to tests/examples/test_contrib/test_sqlalchemy/plugins/test_tutorial_example_apps.py
diff --git a/docs/examples/tests/dependency_injection/__init__.py b/tests/examples/test_dependency_injection/__init__.py
similarity index 100%
rename from docs/examples/tests/dependency_injection/__init__.py
rename to tests/examples/test_dependency_injection/__init__.py
diff --git a/docs/examples/tests/dependency_injection/test_dependency_default_value_no_dependency_fn.py b/tests/examples/test_dependency_injection/test_dependency_default_value_no_dependency_fn.py
similarity index 81%
rename from docs/examples/tests/dependency_injection/test_dependency_default_value_no_dependency_fn.py
rename to tests/examples/test_dependency_injection/test_dependency_default_value_no_dependency_fn.py
--- a/docs/examples/tests/dependency_injection/test_dependency_default_value_no_dependency_fn.py
+++ b/tests/examples/test_dependency_injection/test_dependency_default_value_no_dependency_fn.py
@@ -1,4 +1,5 @@
-from examples.dependency_injection import dependency_default_value_no_dependency_fn
+from docs.examples.dependency_injection import dependency_default_value_no_dependency_fn
+
 from litestar.status_codes import HTTP_200_OK
 from litestar.testing import TestClient
 
diff --git a/docs/examples/tests/dependency_injection/test_dependency_default_value_with_dependency_fn.py b/tests/examples/test_dependency_injection/test_dependency_default_value_with_dependency_fn.py
similarity index 80%
rename from docs/examples/tests/dependency_injection/test_dependency_default_value_with_dependency_fn.py
rename to tests/examples/test_dependency_injection/test_dependency_default_value_with_dependency_fn.py
--- a/docs/examples/tests/dependency_injection/test_dependency_default_value_with_dependency_fn.py
+++ b/tests/examples/test_dependency_injection/test_dependency_default_value_with_dependency_fn.py
@@ -1,4 +1,5 @@
-from examples.dependency_injection import dependency_default_value_with_dependency_fn
+from docs.examples.dependency_injection import dependency_default_value_with_dependency_fn
+
 from litestar.status_codes import HTTP_200_OK
 from litestar.testing import TestClient
 
diff --git a/docs/examples/tests/dependency_injection/test_dependency_skip_validation.py b/tests/examples/test_dependency_injection/test_dependency_skip_validation.py
similarity index 78%
rename from docs/examples/tests/dependency_injection/test_dependency_skip_validation.py
rename to tests/examples/test_dependency_injection/test_dependency_skip_validation.py
--- a/docs/examples/tests/dependency_injection/test_dependency_skip_validation.py
+++ b/tests/examples/test_dependency_injection/test_dependency_skip_validation.py
@@ -1,4 +1,5 @@
-from examples.dependency_injection import dependency_skip_validation
+from docs.examples.dependency_injection import dependency_skip_validation
+
 from litestar.status_codes import HTTP_200_OK
 from litestar.testing import TestClient
 
diff --git a/docs/examples/tests/dependency_injection/test_dependency_validation_error.py b/tests/examples/test_dependency_injection/test_dependency_validation_error.py
similarity index 80%
rename from docs/examples/tests/dependency_injection/test_dependency_validation_error.py
rename to tests/examples/test_dependency_injection/test_dependency_validation_error.py
--- a/docs/examples/tests/dependency_injection/test_dependency_validation_error.py
+++ b/tests/examples/test_dependency_injection/test_dependency_validation_error.py
@@ -1,4 +1,5 @@
-from examples.dependency_injection import dependency_validation_error
+from docs.examples.dependency_injection import dependency_validation_error
+
 from litestar.status_codes import HTTP_500_INTERNAL_SERVER_ERROR
 from litestar.testing import TestClient
 
diff --git a/docs/examples/tests/dependency_injection/tests_dependency_non_optional_not_provided.py b/tests/examples/test_dependency_injection/tests_dependency_non_optional_not_provided.py
similarity index 78%
rename from docs/examples/tests/dependency_injection/tests_dependency_non_optional_not_provided.py
rename to tests/examples/test_dependency_injection/tests_dependency_non_optional_not_provided.py
--- a/docs/examples/tests/dependency_injection/tests_dependency_non_optional_not_provided.py
+++ b/tests/examples/test_dependency_injection/tests_dependency_non_optional_not_provided.py
@@ -1,6 +1,6 @@
 import pytest
+from docs.examples.dependency_injection import dependency_non_optional_not_provided
 
-from examples.dependency_injection import dependency_non_optional_not_provided
 from litestar import Litestar
 from litestar.exceptions import ImproperlyConfiguredException
 
diff --git a/docs/examples/tests/middleware/__init__.py b/tests/examples/test_dto/__init__.py
similarity index 100%
rename from docs/examples/tests/middleware/__init__.py
rename to tests/examples/test_dto/__init__.py
diff --git a/docs/examples/tests/data_transfer_objects/factory/test_example_apps.py b/tests/examples/test_dto/test_example_apps.py
similarity index 100%
rename from docs/examples/tests/data_transfer_objects/factory/test_example_apps.py
rename to tests/examples/test_dto/test_example_apps.py
diff --git a/docs/examples/tests/data_transfer_objects/factory/test_tutorial.py b/tests/examples/test_dto/test_tutorial.py
similarity index 100%
rename from docs/examples/tests/data_transfer_objects/factory/test_tutorial.py
rename to tests/examples/test_dto/test_tutorial.py
diff --git a/docs/examples/tests/test_exceptions.py b/tests/examples/test_exceptions.py
similarity index 97%
rename from docs/examples/tests/test_exceptions.py
rename to tests/examples/test_exceptions.py
--- a/docs/examples/tests/test_exceptions.py
+++ b/tests/examples/test_exceptions.py
@@ -1,8 +1,9 @@
-from examples.exceptions import (
+from docs.examples.exceptions import (
     layered_handlers,
     override_default_handler,
     per_exception_handlers,
 )
+
 from litestar.testing import TestClient
 
 
diff --git a/docs/examples/tests/test_hello_world.py b/tests/examples/test_hello_world.py
similarity index 88%
rename from docs/examples/tests/test_hello_world.py
rename to tests/examples/test_hello_world.py
--- a/docs/examples/tests/test_hello_world.py
+++ b/tests/examples/test_hello_world.py
@@ -1,4 +1,5 @@
-from examples import hello_world
+from docs.examples import hello_world
+
 from litestar.status_codes import HTTP_200_OK
 from litestar.testing import TestClient
 
diff --git a/docs/examples/tests/test_lifecycle_hooks.py b/tests/examples/test_lifecycle_hooks.py
similarity index 81%
rename from docs/examples/tests/test_lifecycle_hooks.py
rename to tests/examples/test_lifecycle_hooks.py
--- a/docs/examples/tests/test_lifecycle_hooks.py
+++ b/tests/examples/test_lifecycle_hooks.py
@@ -1,7 +1,8 @@
-from examples.lifecycle_hooks.after_request import app as after_request_app
-from examples.lifecycle_hooks.after_response import app as after_response_app
-from examples.lifecycle_hooks.before_request import app as before_request_app
-from examples.lifecycle_hooks.layered_hooks import app as layered_hooks_app
+from docs.examples.lifecycle_hooks.after_request import app as after_request_app
+from docs.examples.lifecycle_hooks.after_response import app as after_response_app
+from docs.examples.lifecycle_hooks.before_request import app as before_request_app
+from docs.examples.lifecycle_hooks.layered_hooks import app as layered_hooks_app
+
 from litestar.testing import TestClient
 
 
diff --git a/docs/examples/tests/openapi/__init__.py b/tests/examples/test_middleware/__init__.py
similarity index 100%
rename from docs/examples/tests/openapi/__init__.py
rename to tests/examples/test_middleware/__init__.py
diff --git a/docs/examples/tests/middleware/test_abstract_middleware.py b/tests/examples/test_middleware/test_abstract_middleware.py
similarity index 95%
rename from docs/examples/tests/middleware/test_abstract_middleware.py
rename to tests/examples/test_middleware/test_abstract_middleware.py
--- a/docs/examples/tests/middleware/test_abstract_middleware.py
+++ b/tests/examples/test_middleware/test_abstract_middleware.py
@@ -1,4 +1,5 @@
-from examples.middleware.base import app
+from docs.examples.middleware.base import app
+
 from litestar.status_codes import HTTP_200_OK
 from litestar.testing import TestClient
 
diff --git a/docs/examples/tests/middleware/test_call_order.py b/tests/examples/test_middleware/test_call_order.py
similarity index 83%
rename from docs/examples/tests/middleware/test_call_order.py
rename to tests/examples/test_middleware/test_call_order.py
--- a/docs/examples/tests/middleware/test_call_order.py
+++ b/tests/examples/test_middleware/test_call_order.py
@@ -1,4 +1,5 @@
-from examples.middleware.call_order import app
+from docs.examples.middleware.call_order import app
+
 from litestar.testing import TestClient
 
 
diff --git a/docs/examples/tests/middleware/test_logging_middleware.py b/tests/examples/test_middleware/test_logging_middleware.py
similarity index 56%
rename from docs/examples/tests/middleware/test_logging_middleware.py
rename to tests/examples/test_middleware/test_logging_middleware.py
--- a/docs/examples/tests/middleware/test_logging_middleware.py
+++ b/tests/examples/test_middleware/test_logging_middleware.py
@@ -8,21 +8,9 @@
 
     from litestar.types.callable_types import GetLogger
 
-from examples.middleware.logging_middleware import app
-from litestar.logging.config import LoggingConfig, default_handlers
-from litestar.testing import TestClient
-
+from docs.examples.middleware.logging_middleware import app
 
-@pytest.fixture
-def get_logger() -> "GetLogger":
-    # due to the limitations of caplog we have to place this call here.
-    # we also have to allow propagation.
-    return LoggingConfig(
-        handlers=default_handlers,
-        loggers={
-            "litestar": {"level": "INFO", "handlers": ["queue_listener"], "propagate": True},
-        },
-    ).configure()
+from litestar.testing import TestClient
 
 
 @pytest.mark.usefixtures("reset_httpx_logging")
diff --git a/docs/examples/tests/middleware/test_rate_limit_middleware.py b/tests/examples/test_middleware/test_rate_limit_middleware.py
similarity index 89%
rename from docs/examples/tests/middleware/test_rate_limit_middleware.py
rename to tests/examples/test_middleware/test_rate_limit_middleware.py
--- a/docs/examples/tests/middleware/test_rate_limit_middleware.py
+++ b/tests/examples/test_middleware/test_rate_limit_middleware.py
@@ -1,4 +1,5 @@
-from examples.middleware.rate_limit import app
+from docs.examples.middleware.rate_limit import app
+
 from litestar.status_codes import HTTP_200_OK, HTTP_429_TOO_MANY_REQUESTS
 from litestar.testing import TestClient
 
diff --git a/docs/examples/tests/middleware/test_session_middleware.py b/tests/examples/test_middleware/test_session_middleware.py
similarity index 92%
rename from docs/examples/tests/middleware/test_session_middleware.py
rename to tests/examples/test_middleware/test_session_middleware.py
--- a/docs/examples/tests/middleware/test_session_middleware.py
+++ b/tests/examples/test_middleware/test_session_middleware.py
@@ -1,4 +1,5 @@
-from examples.middleware.session.cookies_full_example import app
+from docs.examples.middleware.session.cookies_full_example import app
+
 from litestar.status_codes import HTTP_200_OK, HTTP_201_CREATED, HTTP_204_NO_CONTENT
 from litestar.testing import TestClient
 
diff --git a/docs/examples/tests/openapi/test_customize_pydantic_model_name.py b/tests/examples/test_openapi.py
similarity index 95%
rename from docs/examples/tests/openapi/test_customize_pydantic_model_name.py
rename to tests/examples/test_openapi.py
--- a/docs/examples/tests/openapi/test_customize_pydantic_model_name.py
+++ b/tests/examples/test_openapi.py
@@ -1,4 +1,5 @@
-from examples.openapi import customize_pydantic_model_name
+from docs.examples.openapi import customize_pydantic_model_name
+
 from litestar.testing import TestClient
 
 
diff --git a/docs/examples/tests/pagination/__init__.py b/tests/examples/test_pagination/__init__.py
similarity index 100%
rename from docs/examples/tests/pagination/__init__.py
rename to tests/examples/test_pagination/__init__.py
diff --git a/docs/examples/tests/pagination/test_using_classic_pagination.py b/tests/examples/test_pagination/test_using_classic_pagination.py
similarity index 88%
rename from docs/examples/tests/pagination/test_using_classic_pagination.py
rename to tests/examples/test_pagination/test_using_classic_pagination.py
--- a/docs/examples/tests/pagination/test_using_classic_pagination.py
+++ b/tests/examples/test_pagination/test_using_classic_pagination.py
@@ -1,4 +1,5 @@
-from examples.pagination.using_classic_pagination import app
+from docs.examples.pagination.using_classic_pagination import app
+
 from litestar.status_codes import HTTP_200_OK
 from litestar.testing import TestClient
 
diff --git a/docs/examples/tests/pagination/test_using_cursor_pagination.py b/tests/examples/test_pagination/test_using_cursor_pagination.py
similarity index 88%
rename from docs/examples/tests/pagination/test_using_cursor_pagination.py
rename to tests/examples/test_pagination/test_using_cursor_pagination.py
--- a/docs/examples/tests/pagination/test_using_cursor_pagination.py
+++ b/tests/examples/test_pagination/test_using_cursor_pagination.py
@@ -1,4 +1,5 @@
-from examples.pagination.using_cursor_pagination import app
+from docs.examples.pagination.using_cursor_pagination import app
+
 from litestar.status_codes import HTTP_200_OK
 from litestar.testing import TestClient
 
diff --git a/docs/examples/tests/pagination/test_using_offset_pagination.py b/tests/examples/test_pagination/test_using_offset_pagination.py
similarity index 88%
rename from docs/examples/tests/pagination/test_using_offset_pagination.py
rename to tests/examples/test_pagination/test_using_offset_pagination.py
--- a/docs/examples/tests/pagination/test_using_offset_pagination.py
+++ b/tests/examples/test_pagination/test_using_offset_pagination.py
@@ -1,4 +1,5 @@
-from examples.pagination.using_offset_pagination import app
+from docs.examples.pagination.using_offset_pagination import app
+
 from litestar.status_codes import HTTP_200_OK
 from litestar.testing import TestClient
 
diff --git a/docs/examples/tests/parameters/__init__.py b/tests/examples/test_parameters/__init__.py
similarity index 100%
rename from docs/examples/tests/parameters/__init__.py
rename to tests/examples/test_parameters/__init__.py
diff --git a/docs/examples/tests/parameters/test_header_and_cookies_parameters.py b/tests/examples/test_parameters/test_header_and_cookies_parameters.py
similarity index 91%
rename from docs/examples/tests/parameters/test_header_and_cookies_parameters.py
rename to tests/examples/test_parameters/test_header_and_cookies_parameters.py
--- a/docs/examples/tests/parameters/test_header_and_cookies_parameters.py
+++ b/tests/examples/test_parameters/test_header_and_cookies_parameters.py
@@ -1,4 +1,5 @@
-from examples.parameters.header_and_cookie_parameters import app
+from docs.examples.parameters.header_and_cookie_parameters import app
+
 from litestar.status_codes import (
     HTTP_200_OK,
     HTTP_400_BAD_REQUEST,
diff --git a/docs/examples/tests/parameters/test_layered_parameters.py b/tests/examples/test_parameters/test_layered_parameters.py
similarity index 96%
rename from docs/examples/tests/parameters/test_layered_parameters.py
rename to tests/examples/test_parameters/test_layered_parameters.py
--- a/docs/examples/tests/parameters/test_layered_parameters.py
+++ b/tests/examples/test_parameters/test_layered_parameters.py
@@ -1,8 +1,8 @@
 from typing import Any, Dict
 
 import pytest
+from docs.examples.parameters.layered_parameters import app
 
-from examples.parameters.layered_parameters import app
 from litestar.testing import TestClient
 
 
diff --git a/docs/examples/tests/parameters/test_path_parameters.py b/tests/examples/test_parameters/test_path_parameters.py
similarity index 80%
rename from docs/examples/tests/parameters/test_path_parameters.py
rename to tests/examples/test_parameters/test_path_parameters.py
--- a/docs/examples/tests/parameters/test_path_parameters.py
+++ b/tests/examples/test_parameters/test_path_parameters.py
@@ -1,6 +1,7 @@
-from examples.parameters.path_parameters_1 import app
-from examples.parameters.path_parameters_2 import app as app_2
-from examples.parameters.path_parameters_3 import app as app_3
+from docs.examples.parameters.path_parameters_1 import app
+from docs.examples.parameters.path_parameters_2 import app as app_2
+from docs.examples.parameters.path_parameters_3 import app as app_3
+
 from litestar.testing import TestClient
 
 
diff --git a/docs/examples/tests/parameters/test_query_parameters.py b/tests/examples/test_parameters/test_query_parameters.py
similarity index 79%
rename from docs/examples/tests/parameters/test_query_parameters.py
rename to tests/examples/test_parameters/test_query_parameters.py
--- a/docs/examples/tests/parameters/test_query_parameters.py
+++ b/tests/examples/test_parameters/test_query_parameters.py
@@ -1,11 +1,12 @@
-from examples.parameters.query_params import app as query_params_app
-from examples.parameters.query_params_constraints import (
+from docs.examples.parameters.query_params import app as query_params_app
+from docs.examples.parameters.query_params_constraints import (
     app as query_params_constraints_app,
 )
-from examples.parameters.query_params_default import app as query_params_default_app
-from examples.parameters.query_params_optional import app as query_params_optional_app
-from examples.parameters.query_params_remap import app as query_params_remap_app
-from examples.parameters.query_params_types import app as query_params_types_app
+from docs.examples.parameters.query_params_default import app as query_params_default_app
+from docs.examples.parameters.query_params_optional import app as query_params_optional_app
+from docs.examples.parameters.query_params_remap import app as query_params_remap_app
+from docs.examples.parameters.query_params_types import app as query_params_types_app
+
 from litestar.testing import TestClient
 
 
diff --git a/docs/examples/tests/plugins/__init__.py b/tests/examples/test_plugins/__init__.py
similarity index 100%
rename from docs/examples/tests/plugins/__init__.py
rename to tests/examples/test_plugins/__init__.py
diff --git a/docs/examples/tests/plugins/test_example_apps.py b/tests/examples/test_plugins/test_example_apps.py
similarity index 100%
rename from docs/examples/tests/plugins/test_example_apps.py
rename to tests/examples/test_plugins/test_example_apps.py
diff --git a/docs/examples/tests/plugins/test_sqlalchemy_init_plugin.py b/tests/examples/test_plugins/test_sqlalchemy_init_plugin.py
similarity index 69%
rename from docs/examples/tests/plugins/test_sqlalchemy_init_plugin.py
rename to tests/examples/test_plugins/test_sqlalchemy_init_plugin.py
--- a/docs/examples/tests/plugins/test_sqlalchemy_init_plugin.py
+++ b/tests/examples/test_plugins/test_sqlalchemy_init_plugin.py
@@ -3,9 +3,9 @@
 from typing import TYPE_CHECKING
 
 import pytest
+from docs.examples.plugins.sqlalchemy_init_plugin.sqlalchemy_async import app as async_sqla_app
+from docs.examples.plugins.sqlalchemy_init_plugin.sqlalchemy_sync import app as sync_sqla_app
 
-from examples.plugins.sqlalchemy_init_plugin.sqlalchemy_async import app as async_sqla_app
-from examples.plugins.sqlalchemy_init_plugin.sqlalchemy_sync import app as sync_sqla_app
 from litestar.testing import TestClient
 
 if TYPE_CHECKING:
diff --git a/docs/examples/tests/request_data/test_request_data.py b/tests/examples/test_request_data.py
similarity index 73%
rename from docs/examples/tests/request_data/test_request_data.py
rename to tests/examples/test_request_data.py
--- a/docs/examples/tests/request_data/test_request_data.py
+++ b/tests/examples/test_request_data.py
@@ -1,13 +1,16 @@
-from examples.request_data.request_data_1 import app
-from examples.request_data.request_data_2 import app as app_2
-from examples.request_data.request_data_3 import app as app_3
-from examples.request_data.request_data_4 import app as app_4
-from examples.request_data.request_data_5 import app as app_5
-from examples.request_data.request_data_6 import app as app_6
-from examples.request_data.request_data_7 import app as app_7
-from examples.request_data.request_data_8 import app as app_8
-from examples.request_data.request_data_9 import app as app_9
-from examples.request_data.request_data_10 import app as app_10
+from docs.examples.request_data.msgpack_request import app as msgpack_app
+from docs.examples.request_data.request_data_1 import app
+from docs.examples.request_data.request_data_2 import app as app_2
+from docs.examples.request_data.request_data_3 import app as app_3
+from docs.examples.request_data.request_data_4 import app as app_4
+from docs.examples.request_data.request_data_5 import app as app_5
+from docs.examples.request_data.request_data_6 import app as app_6
+from docs.examples.request_data.request_data_7 import app as app_7
+from docs.examples.request_data.request_data_8 import app as app_8
+from docs.examples.request_data.request_data_9 import app as app_9
+from docs.examples.request_data.request_data_10 import app as app_10
+
+from litestar.serialization import encode_msgpack
 from litestar.testing import TestClient
 
 
@@ -86,3 +89,11 @@ def test_request_data_10() -> None:
         res = client.post("/", files={"foo": ("foo.txt", b"hello"), "bar": ("bar.txt", b"world")})
         assert res.status_code == 201
         assert res.json() == {"foo.txt": "hello", "bar.txt": "world"}
+
+
+def test_msgpack_app() -> None:
+    test_data = {"name": "Moishe Zuchmir", "age": 30, "programmer": True}
+
+    with TestClient(app=msgpack_app) as client:
+        response = client.post("/", content=encode_msgpack(test_data))
+        assert response.json() == test_data
diff --git a/docs/examples/tests/responses/__init__.py b/tests/examples/test_responses/__init__.py
similarity index 100%
rename from docs/examples/tests/responses/__init__.py
rename to tests/examples/test_responses/__init__.py
diff --git a/docs/examples/tests/responses/test_background_tasks.py b/tests/examples/test_responses/test_background_tasks.py
similarity index 82%
rename from docs/examples/tests/responses/test_background_tasks.py
rename to tests/examples/test_responses/test_background_tasks.py
--- a/docs/examples/tests/responses/test_background_tasks.py
+++ b/tests/examples/test_responses/test_background_tasks.py
@@ -2,11 +2,11 @@
 from typing import TYPE_CHECKING
 
 import pytest
+from docs.examples.responses.background_tasks_1 import app as app_1
+from docs.examples.responses.background_tasks_2 import app as app_2
+from docs.examples.responses.background_tasks_3 import app as app_3
+from docs.examples.responses.background_tasks_3 import greeted as greeted_3
 
-from examples.responses.background_tasks_1 import app as app_1
-from examples.responses.background_tasks_2 import app as app_2
-from examples.responses.background_tasks_3 import app as app_3
-from examples.responses.background_tasks_3 import greeted as greeted_3
 from litestar.testing import TestClient
 
 if TYPE_CHECKING:
diff --git a/docs/examples/tests/responses/test_custom_responses.py b/tests/examples/test_responses/test_custom_responses.py
similarity index 78%
rename from docs/examples/tests/responses/test_custom_responses.py
rename to tests/examples/test_responses/test_custom_responses.py
--- a/docs/examples/tests/responses/test_custom_responses.py
+++ b/tests/examples/test_responses/test_custom_responses.py
@@ -1,4 +1,5 @@
-from examples.responses.custom_responses import app as app_1
+from docs.examples.responses.custom_responses import app as app_1
+
 from litestar.testing import TestClient
 
 
diff --git a/docs/examples/tests/responses/test_response_cookies.py b/tests/examples/test_responses/test_response_cookies.py
similarity index 66%
rename from docs/examples/tests/responses/test_response_cookies.py
rename to tests/examples/test_responses/test_response_cookies.py
--- a/docs/examples/tests/responses/test_response_cookies.py
+++ b/tests/examples/test_responses/test_response_cookies.py
@@ -1,10 +1,11 @@
 from unittest.mock import patch
 
-from examples.responses.response_cookies_1 import app
-from examples.responses.response_cookies_2 import app as app_2
-from examples.responses.response_cookies_3 import app as app_3
-from examples.responses.response_cookies_4 import app as app_4
-from examples.responses.response_cookies_5 import app as app_5
+from docs.examples.responses.response_cookies_1 import app
+from docs.examples.responses.response_cookies_2 import app as app_2
+from docs.examples.responses.response_cookies_3 import app as app_3
+from docs.examples.responses.response_cookies_4 import app as app_4
+from docs.examples.responses.response_cookies_5 import app as app_5
+
 from litestar.testing import TestClient
 
 
@@ -26,7 +27,7 @@ def test_response_cookies_2() -> None:
 
 
 def test_response_cookies_3() -> None:
-    with TestClient(app=app_3) as client, patch("examples.responses.response_cookies_3.randint") as mock_randint:
+    with TestClient(app=app_3) as client, patch("docs.examples.responses.response_cookies_3.randint") as mock_randint:
         mock_randint.return_value = "42"
 
         res = client.get("/resources")
@@ -36,7 +37,7 @@ def test_response_cookies_3() -> None:
 
 
 def test_response_cookies_4() -> None:
-    with TestClient(app=app_4) as client, patch("examples.responses.response_cookies_4.randint") as mock_randint:
+    with TestClient(app=app_4) as client, patch("docs.examples.responses.response_cookies_4.randint") as mock_randint:
         mock_randint.return_value = "42"
 
         res = client.get("/router-path/resources")
@@ -46,7 +47,7 @@ def test_response_cookies_4() -> None:
 
 
 def test_response_cookies_5() -> None:
-    with TestClient(app=app_5) as client, patch("examples.responses.response_cookies_5.randint") as mock_randint:
+    with TestClient(app=app_5) as client, patch("docs.examples.responses.response_cookies_5.randint") as mock_randint:
         mock_randint.return_value = "42"
 
         res = client.get("/router-path/resources")
diff --git a/docs/examples/tests/responses/test_response_headers.py b/tests/examples/test_responses/test_response_headers.py
similarity index 67%
rename from docs/examples/tests/responses/test_response_headers.py
rename to tests/examples/test_responses/test_response_headers.py
--- a/docs/examples/tests/responses/test_response_headers.py
+++ b/tests/examples/test_responses/test_response_headers.py
@@ -1,9 +1,10 @@
 from unittest.mock import patch
 
-from examples.responses.response_headers_1 import app
-from examples.responses.response_headers_2 import app as app_2
-from examples.responses.response_headers_3 import app as app_3
-from examples.responses.response_headers_4 import app as app_4
+from docs.examples.responses.response_headers_1 import app
+from docs.examples.responses.response_headers_2 import app as app_2
+from docs.examples.responses.response_headers_3 import app as app_3
+from docs.examples.responses.response_headers_4 import app as app_4
+
 from litestar.testing import TestClient
 
 
@@ -18,7 +19,7 @@ def test_response_headers() -> None:
 
 
 def test_response_headers_2() -> None:
-    with TestClient(app=app_2) as client, patch("examples.responses.response_headers_2.randint") as mock_randint:
+    with TestClient(app=app_2) as client, patch("docs.examples.responses.response_headers_2.randint") as mock_randint:
         mock_randint.return_value = "42"
         res = client.get("/resources")
         assert res.status_code == 200
@@ -26,7 +27,7 @@ def test_response_headers_2() -> None:
 
 
 def test_response_headers_3() -> None:
-    with TestClient(app=app_3) as client, patch("examples.responses.response_headers_3.randint") as mock_randint:
+    with TestClient(app=app_3) as client, patch("docs.examples.responses.response_headers_3.randint") as mock_randint:
         mock_randint.return_value = "42"
         res = client.get("/router-path/resources")
         assert res.status_code == 200
@@ -35,7 +36,7 @@ def test_response_headers_3() -> None:
 
 
 def test_response_headers_4() -> None:
-    with TestClient(app=app_4) as client, patch("examples.responses.response_headers_4.randint") as mock_randint:
+    with TestClient(app=app_4) as client, patch("docs.examples.responses.response_headers_4.randint") as mock_randint:
         mock_randint.return_value = "42"
         res = client.get("/router-path/resources")
         assert res.status_code == 200
diff --git a/docs/examples/tests/responses/test_returning_responses.py b/tests/examples/test_responses/test_returning_responses.py
similarity index 84%
rename from docs/examples/tests/responses/test_returning_responses.py
rename to tests/examples/test_responses/test_returning_responses.py
--- a/docs/examples/tests/responses/test_returning_responses.py
+++ b/tests/examples/test_responses/test_returning_responses.py
@@ -1,4 +1,5 @@
-from examples.responses.returning_responses import app
+from docs.examples.responses.returning_responses import app
+
 from litestar.testing import TestClient
 
 
diff --git a/docs/examples/tests/routing/test_mounting.py b/tests/examples/test_routing.py
similarity index 92%
rename from docs/examples/tests/routing/test_mounting.py
rename to tests/examples/test_routing.py
--- a/docs/examples/tests/routing/test_mounting.py
+++ b/tests/examples/test_routing.py
@@ -1,8 +1,8 @@
 from typing import TYPE_CHECKING
 
 import pytest
+from docs.examples.routing import mount_custom_app, mounting_starlette_app
 
-from examples.routing import mount_custom_app, mounting_starlette_app
 from litestar.status_codes import HTTP_200_OK
 from litestar.testing import TestClient
 
diff --git a/docs/examples/tests/test_signature_namespace.py b/tests/examples/test_signature_namespace.py
similarity index 81%
rename from docs/examples/tests/test_signature_namespace.py
rename to tests/examples/test_signature_namespace.py
--- a/docs/examples/tests/test_signature_namespace.py
+++ b/tests/examples/test_signature_namespace.py
@@ -1,4 +1,5 @@
-from examples.signature_namespace.app import app
+from docs.examples.signature_namespace.app import app
+
 from litestar.testing import TestClient
 
 
diff --git a/docs/examples/tests/test_startup_and_shutdown.py b/tests/examples/test_startup_and_shutdown.py
similarity index 94%
rename from docs/examples/tests/test_startup_and_shutdown.py
rename to tests/examples/test_startup_and_shutdown.py
--- a/docs/examples/tests/test_startup_and_shutdown.py
+++ b/tests/examples/test_startup_and_shutdown.py
@@ -1,7 +1,8 @@
 from typing import TYPE_CHECKING
 from unittest.mock import AsyncMock, MagicMock
 
-from examples import startup_and_shutdown
+from docs.examples import startup_and_shutdown
+
 from litestar import get
 from litestar.datastructures import State
 from litestar.testing import TestClient
diff --git a/docs/examples/tests/test_stores.py b/tests/examples/test_stores.py
similarity index 73%
rename from docs/examples/tests/test_stores.py
rename to tests/examples/test_stores.py
--- a/docs/examples/tests/test_stores.py
+++ b/tests/examples/test_stores.py
@@ -1,9 +1,7 @@
 from pathlib import Path
-from typing import TYPE_CHECKING, Generator
 from unittest.mock import MagicMock, patch
 
 import anyio
-from freezegun import freeze_time
 
 from litestar import get
 from litestar.stores.file import FileStore
@@ -11,23 +9,10 @@
 from litestar.stores.redis import RedisStore
 from litestar.testing import TestClient
 
-if TYPE_CHECKING:
-    from freezegun.api import FrozenDateTimeFactory
-
-from typing import cast
-
-import pytest
-
-
-@pytest.fixture()
-def frozen_datetime() -> Generator["FrozenDateTimeFactory", None, None]:
-    with freeze_time() as frozen:
-        yield cast("FrozenDateTimeFactory", frozen)
-
 
 @patch("litestar.stores.redis.Redis")
 async def test_configure_integrations_set_names(mock_redis: MagicMock) -> None:
-    from examples.stores.configure_integrations_set_names import app
+    from docs.examples.stores.configure_integrations_set_names import app
 
     assert isinstance(app.stores.get("redis"), RedisStore)
     assert isinstance(app.stores.get("file"), FileStore)
@@ -35,7 +20,7 @@ async def test_configure_integrations_set_names(mock_redis: MagicMock) -> None:
 
 
 async def test_delete_expired_after_response(frozen_datetime) -> None:
-    from examples.stores.delete_expired_after_response import app, memory_store
+    from docs.examples.stores.delete_expired_after_response import app, memory_store
 
     @get()
     async def handler() -> bytes:
@@ -52,7 +37,7 @@ async def handler() -> bytes:
 
 
 async def test_delete_expired_on_startup(tmp_path) -> None:
-    from examples.stores.delete_expired_on_startup import app, file_store
+    from docs.examples.stores.delete_expired_on_startup import app, file_store
 
     file_store.path = anyio.Path(tmp_path)
 
@@ -64,7 +49,7 @@ async def test_delete_expired_on_startup(tmp_path) -> None:
 
 
 async def test_get_set(capsys) -> None:
-    from examples.stores.get_set import main
+    from docs.examples.stores.get_set import main
 
     await main()
 
@@ -72,7 +57,7 @@ async def test_get_set(capsys) -> None:
 
 
 async def test_registry() -> None:
-    from examples.stores.registry import app, memory_store, some_other_store
+    from docs.examples.stores.registry import app, memory_store, some_other_store
 
     assert app.stores.get("memory") is memory_store
     assert isinstance(memory_store, MemoryStore)
@@ -81,7 +66,7 @@ async def test_registry() -> None:
 
 
 async def test_registry_access_integration() -> None:
-    from examples.stores.registry_access_integration import app, rate_limit_store
+    from docs.examples.stores.registry_access_integration import app, rate_limit_store
 
     assert app.stores.get("rate_limit") is rate_limit_store
     # this is a weird assertion but the easiest way to check if our example is correct
@@ -90,7 +75,7 @@ async def test_registry_access_integration() -> None:
 
 @patch("litestar.stores.redis.Redis")
 async def test_configure_integrations(mock_redis: MagicMock) -> None:
-    from examples.stores.registry_configure_integrations import app
+    from docs.examples.stores.registry_configure_integrations import app
 
     session_store = app.middleware[0].kwargs["backend"].config.get_store_from_app(app)
     cache_store = app.response_cache_config.get_store_from_app(app)
@@ -101,7 +86,7 @@ async def test_configure_integrations(mock_redis: MagicMock) -> None:
 
 
 async def test_registry_default_factory() -> None:
-    from examples.stores.registry_default_factory import app, memory_store
+    from docs.examples.stores.registry_default_factory import app, memory_store
 
     assert app.stores.get("foo") is memory_store
     assert app.stores.get("bar") is memory_store
@@ -109,7 +94,7 @@ async def test_registry_default_factory() -> None:
 
 @patch("litestar.stores.redis.Redis")
 async def test_default_factory_namespacing(mock_redis: MagicMock) -> None:
-    from examples.stores.registry_default_factory_namespacing import app, root_store
+    from docs.examples.stores.registry_default_factory_namespacing import app, root_store
 
     foo_store = app.stores.get("foo")
     assert isinstance(foo_store, RedisStore)
diff --git a/docs/examples/tests/security/test_using_session_auth.py b/tests/examples/test_using_session_auth.py
similarity index 95%
rename from docs/examples/tests/security/test_using_session_auth.py
rename to tests/examples/test_using_session_auth.py
--- a/docs/examples/tests/security/test_using_session_auth.py
+++ b/tests/examples/test_using_session_auth.py
@@ -1,4 +1,5 @@
-from examples.security.using_session_auth import app
+from docs.examples.security.using_session_auth import app
+
 from litestar.status_codes import HTTP_200_OK, HTTP_201_CREATED, HTTP_401_UNAUTHORIZED
 from litestar.testing import TestClient
 
diff --git a/tests/middleware/conftest.py b/tests/middleware/conftest.py
deleted file mode 100644
--- a/tests/middleware/conftest.py
+++ /dev/null
@@ -1,20 +0,0 @@
-from typing import TYPE_CHECKING
-
-import pytest
-
-from litestar.logging.config import LoggingConfig, default_handlers
-
-if TYPE_CHECKING:
-    from litestar.types.callable_types import GetLogger
-
-
-@pytest.fixture
-def get_logger() -> "GetLogger":
-    # due to the limitations of caplog we have to place this call here.
-    # we also have to allow propagation.
-    return LoggingConfig(
-        handlers=default_handlers,
-        loggers={
-            "litestar": {"level": "DEBUG", "handlers": ["queue_listener"], "propagate": True},
-        },
-    ).configure()
diff --git a/tests/openapi/typescript_converter/__init__.py b/tests/openapi/typescript_converter/__init__.py
deleted file mode 100644
diff --git a/tests/piccolo_conf.py b/tests/piccolo_conf.py
deleted file mode 100644
--- a/tests/piccolo_conf.py
+++ /dev/null
@@ -1,6 +0,0 @@
-from piccolo.conf.apps import AppRegistry
-from piccolo.engine import SQLiteEngine
-
-DB = SQLiteEngine(path="test.sqlite")
-
-APP_REGISTRY = AppRegistry(apps=["tests.contrib.piccolo_orm.piccolo_app"])
diff --git a/tests/response/__init__.py b/tests/response/__init__.py
deleted file mode 100644
diff --git a/tests/routing/__init__.py b/tests/routing/__init__.py
deleted file mode 100644
diff --git a/tests/security/__init__.py b/tests/security/__init__.py
deleted file mode 100644
diff --git a/tests/signature/__init__.py b/tests/signature/__init__.py
deleted file mode 100644
diff --git a/tests/static_files/__init__.py b/tests/static_files/__init__.py
deleted file mode 100644
diff --git a/tests/template/__init__.py b/tests/template/__init__.py
deleted file mode 100644
diff --git a/tests/test_parameters.py b/tests/test_parameters.py
deleted file mode 100644
--- a/tests/test_parameters.py
+++ /dev/null
@@ -1,88 +0,0 @@
-from typing import Any, List
-
-import pytest
-from typing_extensions import Annotated
-
-from litestar import get, post
-from litestar.di import Provide
-from litestar.params import Body, Dependency, Parameter
-from litestar.status_codes import HTTP_200_OK, HTTP_201_CREATED, HTTP_400_BAD_REQUEST
-from litestar.testing import create_test_client
-
-
-@pytest.mark.parametrize("backend", ("pydantic", "attrs"))
-def test_parsing_of_parameter_as_annotated(backend: Any) -> None:
-    @get(path="/")
-    def handler(param: Annotated[str, Parameter(min_length=1)]) -> str:
-        return param
-
-    with create_test_client(handler, _preferred_validation_backend=backend) as client:
-        response = client.get("/")
-        assert response.status_code == HTTP_400_BAD_REQUEST
-
-        response = client.get("/?param=a")
-        assert response.status_code == HTTP_200_OK
-
-
-@pytest.mark.parametrize("backend", ("pydantic", "attrs"))
-def test_parsing_of_parameter_as_default_value(backend: Any) -> None:
-    @get(path="/")
-    def handler(param: str = Parameter(min_length=1)) -> str:
-        return param
-
-    with create_test_client(handler, _preferred_validation_backend=backend) as client:
-        response = client.get("/?param=")
-        assert response.status_code == HTTP_400_BAD_REQUEST
-
-        response = client.get("/?param=a")
-        assert response.status_code == HTTP_200_OK
-
-
-@pytest.mark.parametrize("backend", ("pydantic", "attrs"))
-def test_parsing_of_body_as_annotated(backend: Any) -> None:
-    @post(path="/")
-    def handler(data: Annotated[List[str], Body(min_items=1)]) -> List[str]:
-        return data
-
-    with create_test_client(handler, _preferred_validation_backend=backend) as client:
-        response = client.post("/", json=[])
-        assert response.status_code == HTTP_400_BAD_REQUEST
-
-        response = client.post("/", json=["a"])
-        assert response.status_code == HTTP_201_CREATED
-
-
-@pytest.mark.parametrize("backend", ("pydantic", "attrs"))
-def test_parsing_of_body_as_default_value(backend: Any) -> None:
-    @post(path="/")
-    def handler(data: List[str] = Body(min_items=1)) -> List[str]:
-        return data
-
-    with create_test_client(handler, _preferred_validation_backend=backend) as client:
-        response = client.post("/", json=[])
-        assert response.status_code == HTTP_400_BAD_REQUEST
-
-        response = client.post("/", json=["a"])
-        assert response.status_code == HTTP_201_CREATED
-
-
-@pytest.mark.parametrize("backend", ("pydantic", "attrs"))
-def test_parsing_of_dependency_as_annotated(backend: Any) -> None:
-    @get(path="/", dependencies={"dep": Provide(lambda: None, sync_to_thread=False)})
-    def handler(dep: Annotated[int, Dependency(skip_validation=True)]) -> int:
-        return dep
-
-    with create_test_client(handler, _preferred_validation_backend=backend) as client:
-        response = client.get("/")
-        assert response.text == "null"
-
-
-@pytest.mark.parametrize("backend", ("pydantic", "attrs"))
-def test_parsing_of_dependency_as_default_value(backend: Any) -> None:
-    @get(path="/", dependencies={"dep": Provide(lambda: None, sync_to_thread=False)})
-    def handler(dep: int = Dependency(skip_validation=True)) -> int:
-        return dep
-
-    with create_test_client(handler, _preferred_validation_backend=backend) as client:
-        response = client.get("/")
-        assert response.text == "null"
diff --git a/tests/test_provide.py b/tests/test_provide.py
deleted file mode 100644
--- a/tests/test_provide.py
+++ /dev/null
@@ -1,208 +0,0 @@
-from functools import partial
-from typing import Any, AsyncGenerator, Generator
-from unittest.mock import MagicMock
-
-import pytest
-
-from litestar._kwargs.cleanup import DependencyCleanupGroup
-from litestar.di import Provide
-from litestar.exceptions import LitestarWarning
-from litestar.types import Empty
-from litestar.utils.compat import async_next
-
-
-class C:
-    val = 31
-
-    def __init__(self) -> None:
-        self.val = 13
-
-    @classmethod
-    async def async_class(cls) -> int:
-        return cls.val
-
-    @classmethod
-    def sync_class(cls) -> int:
-        return cls.val
-
-    @staticmethod
-    async def async_static() -> str:
-        return "one-three"
-
-    @staticmethod
-    def sync_static() -> str:
-        return "one-three"
-
-    async def async_instance(self) -> int:
-        return self.val
-
-    def sync_instance(self) -> int:
-        return self.val
-
-
-async def async_fn(val: str = "three-one") -> str:
-    return val
-
-
-def sync_fn(val: str = "three-one") -> str:
-    return val
-
-
-async_partial = partial(async_fn, "why-three-and-one")
-sync_partial = partial(sync_fn, "why-three-and-one")
-
-
-async def test_provide_default(anyio_backend: str) -> None:
-    provider = Provide(dependency=async_fn)
-    value = await provider()
-    assert value == "three-one"
-
-
-async def test_provide_cached(anyio_backend: str) -> None:
-    provider = Provide(dependency=async_fn, use_cache=True)
-    assert provider.value is Empty
-    value = await provider()
-    assert value == "three-one"
-    assert provider.value == value
-    second_value = await provider()
-    assert value == second_value
-    third_value = await provider()
-    assert value == third_value
-
-
-async def test_run_in_thread(anyio_backend: str) -> None:
-    provider = Provide(dependency=sync_fn, sync_to_thread=True)
-    value = await provider()
-    assert value == "three-one"
-
-
-def test_provider_equality_check() -> None:
-    first_provider = Provide(dependency=sync_fn, sync_to_thread=False)
-    second_provider = Provide(dependency=sync_fn, sync_to_thread=False)
-    assert first_provider == second_provider
-    third_provider = Provide(dependency=sync_fn, use_cache=True, sync_to_thread=False)
-    assert first_provider != third_provider
-    second_provider.value = True
-    assert first_provider != second_provider
-
-
-@pytest.mark.parametrize(
-    "fn, exp",
-    [
-        (C.async_class, 31),
-        (C.sync_class, 31),
-        (C.async_static, "one-three"),
-        (C.sync_static, "one-three"),
-        (C().async_instance, 13),
-        (C().sync_instance, 13),
-        (async_fn, "three-one"),
-        (sync_fn, "three-one"),
-        (async_partial, "why-three-and-one"),
-        (sync_partial, "why-three-and-one"),
-    ],
-)
-@pytest.mark.usefixtures("disable_warn_sync_to_thread_with_async")
-async def test_provide_for_callable(fn: Any, exp: Any, anyio_backend: str) -> None:
-    assert await Provide(fn, sync_to_thread=False)() == exp
-
-
-@pytest.fixture
-def cleanup_mock() -> MagicMock:
-    return MagicMock()
-
-
-@pytest.fixture
-def async_cleanup_mock() -> MagicMock:
-    return MagicMock()
-
-
-@pytest.fixture
-def generator(cleanup_mock: MagicMock) -> Generator[str, None, None]:
-    def func() -> Generator[str, None, None]:
-        yield "hello"
-        cleanup_mock()
-
-    return func()
-
-
-@pytest.fixture
-def async_generator(async_cleanup_mock: MagicMock) -> AsyncGenerator[str, None]:
-    async def func() -> AsyncGenerator[str, None]:
-        yield "world"
-        async_cleanup_mock()
-
-    return func()
-
-
-def test_cleanup_group_add(generator: Generator[str, None, None]) -> None:
-    group = DependencyCleanupGroup()
-
-    group.add(generator)
-
-    assert group._generators == [generator]
-
-
-async def test_cleanup_group_cleanup(generator: Generator[str, None, None], cleanup_mock: MagicMock) -> None:
-    next(generator)
-    group = DependencyCleanupGroup([generator])
-
-    await group.cleanup()
-
-    cleanup_mock.assert_called_once()
-    assert group._closed
-
-
-async def test_cleanup_group_cleanup_multiple(
-    generator: Generator[str, None, None],
-    async_generator: AsyncGenerator[str, None],
-    cleanup_mock: MagicMock,
-    async_cleanup_mock: MagicMock,
-) -> None:
-    next(generator)
-    await async_next(async_generator)
-    group = DependencyCleanupGroup([generator, async_generator])
-
-    await group.cleanup()
-
-    cleanup_mock.assert_called_once()
-    async_cleanup_mock.assert_called_once()
-    assert group._closed
-
-
-async def test_cleanup_group_cleanup_on_closed_raises(generator: Generator[str, None, None]) -> None:
-    next(generator)
-    group = DependencyCleanupGroup([generator])
-
-    await group.cleanup()
-    with pytest.raises(RuntimeError):
-        await group.cleanup()
-
-
-async def test_cleanup_group_add_on_closed_raises(
-    generator: Generator[str, None, None], async_generator: AsyncGenerator[str, None]
-) -> None:
-    next(generator)
-    group = DependencyCleanupGroup([generator])
-
-    await group.cleanup()
-
-    with pytest.raises(RuntimeError):
-        group.add(async_generator)
-
-
-@pytest.mark.usefixtures("enable_warn_implicit_sync_to_thread")
-def test_sync_callable_without_sync_to_thread_warns() -> None:
-    def func() -> None:
-        pass
-
-    with pytest.warns(LitestarWarning, match="discouraged since synchronous callables"):
-        Provide(func)
-
-
-@pytest.mark.parametrize("sync_to_thread", [True, False])
-def test_async_callable_with_sync_to_thread_warns(sync_to_thread: bool) -> None:
-    async def func() -> None:
-        pass
-
-    with pytest.warns(LitestarWarning, match="asynchronous callable"):
-        Provide(func, sync_to_thread=sync_to_thread)
diff --git a/tests/test_response_containers.py b/tests/test_response_containers.py
deleted file mode 100644
--- a/tests/test_response_containers.py
+++ /dev/null
@@ -1,187 +0,0 @@
-import os
-from os import stat
-from pathlib import Path
-from typing import TYPE_CHECKING, Optional
-
-import pytest
-from fsspec.implementations.local import LocalFileSystem
-
-from litestar import get
-from litestar.datastructures import ETag
-from litestar.exceptions import ImproperlyConfiguredException
-from litestar.file_system import BaseLocalFileSystem
-from litestar.response.file import File
-from litestar.response.redirect import Redirect
-from litestar.status_codes import HTTP_200_OK
-from litestar.testing import create_test_client
-
-if TYPE_CHECKING:
-    from litestar.types import FileSystemProtocol
-
-
-@pytest.mark.parametrize("file_system", (BaseLocalFileSystem(), LocalFileSystem()))
-def test_file_with_different_file_systems(tmpdir: "Path", file_system: "FileSystemProtocol") -> None:
-    path = tmpdir / "text.txt"
-    path.write_text("content", "utf-8")
-
-    @get("/", media_type="application/octet-stream")
-    def handler() -> File:
-        return File(
-            filename="text.txt",
-            path=path,
-            file_system=file_system,
-        )
-
-    with create_test_client(handler, debug=True) as client:
-        response = client.get("/")
-        assert response.status_code == HTTP_200_OK
-        assert response.text == "content"
-        assert response.headers.get("content-disposition") == 'attachment; filename="text.txt"'
-
-
-def test_file_with_passed_in_file_info(tmpdir: "Path") -> None:
-    path = tmpdir / "text.txt"
-    path.write_text("content", "utf-8")
-
-    fs = LocalFileSystem()
-    fs_info = fs.info(tmpdir / "text.txt")
-
-    assert fs_info
-
-    @get("/", media_type="application/octet-stream")
-    def handler() -> File:
-        return File(filename="text.txt", path=path, file_system=fs, file_info=fs_info)  # pyright: ignore
-
-    with create_test_client(handler) as client:
-        response = client.get("/")
-        assert response.status_code == HTTP_200_OK, response.text
-        assert response.text == "content"
-        assert response.headers.get("content-disposition") == 'attachment; filename="text.txt"'
-
-
-def test_file_with_passed_in_stat_result(tmpdir: "Path") -> None:
-    path = tmpdir / "text.txt"
-    path.write_text("content", "utf-8")
-
-    fs = LocalFileSystem()
-    stat_result = stat(path)
-
-    @get("/", media_type="application/octet-stream")
-    def handler() -> File:
-        return File(filename="text.txt", path=path, file_system=fs, stat_result=stat_result)
-
-    with create_test_client(handler) as client:
-        response = client.get("/")
-        assert response.status_code == HTTP_200_OK
-        assert response.text == "content"
-        assert response.headers.get("content-disposition") == 'attachment; filename="text.txt"'
-
-
-async def test_file_with_symbolic_link(tmpdir: "Path") -> None:
-    path = tmpdir / "text.txt"
-    path.write_text("content", "utf-8")
-
-    linked = tmpdir / "alt.txt"
-    os.symlink(path, linked, target_is_directory=False)
-
-    fs = BaseLocalFileSystem()
-    file_info = await fs.info(linked)
-
-    assert file_info["islink"]
-
-    @get("/", media_type="application/octet-stream")
-    def handler() -> File:
-        return File(filename="alt.txt", path=linked, file_system=fs, file_info=file_info)
-
-    with create_test_client(handler) as client:
-        response = client.get("/")
-        assert response.status_code == HTTP_200_OK
-        assert response.text == "content"
-        assert response.headers.get("content-disposition") == 'attachment; filename="alt.txt"'
-
-
-async def test_file_sets_etag_correctly(tmpdir: "Path") -> None:
-    path = tmpdir / "file.txt"
-    content = b"<file content>"
-    Path(path).write_bytes(content)
-    etag = ETag(value="special")
-
-    @get("/")
-    def handler() -> File:
-        return File(path=path, etag=etag)
-
-    with create_test_client(handler) as client:
-        response = client.get("/")
-        assert response.status_code == HTTP_200_OK
-        assert response.headers["etag"] == '"special"'
-
-
-def test_file_system_validation(tmpdir: "Path") -> None:
-    path = tmpdir / "text.txt"
-    path.write_text("content", "utf-8")
-
-    class FSWithoutOpen:
-        def info(self) -> None:
-            return
-
-    with pytest.raises(ImproperlyConfiguredException):
-        File(
-            filename="text.txt",
-            path=path,
-            file_system=FSWithoutOpen(),  # type:ignore[arg-type]
-        )
-
-    class FSWithoutInfo:
-        def open(self) -> None:
-            return
-
-    with pytest.raises(ImproperlyConfiguredException):
-        File(
-            filename="text.txt",
-            path=path,
-            file_system=FSWithoutInfo(),  # type:ignore[arg-type]
-        )
-
-    class ImplementedFS:
-        def info(self) -> None:
-            return
-
-        def open(self) -> None:
-            return
-
-    assert File(
-        filename="text.txt",
-        path=path,
-        file_system=ImplementedFS(),  # type:ignore[arg-type]
-    )
-
-
-@pytest.mark.parametrize(
-    "status_code,expected_status_code",
-    [
-        (301, 301),
-        (302, 302),
-        (303, 303),
-        (307, 307),
-        (308, 308),
-    ],
-)
-def test_redirect_dynamic_status_code(status_code: Optional[int], expected_status_code: int) -> None:
-    @get("/")
-    def handler() -> Redirect:
-        return Redirect(path="/something-else", status_code=status_code)  # type: ignore[arg-type]
-
-    with create_test_client([handler], debug=True) as client:
-        res = client.get("/", follow_redirects=False)
-        assert res.status_code == expected_status_code
-
-
-@pytest.mark.parametrize("handler_status_code", [301, 307, None])
-def test_redirect(handler_status_code: Optional[int]) -> None:
-    @get("/", status_code=handler_status_code)
-    def handler() -> Redirect:
-        return Redirect(path="/something-else", status_code=301)
-
-    with create_test_client([handler]) as client:
-        res = client.get("/", follow_redirects=False)
-        assert res.status_code == 301
diff --git a/tests/test_utils.py b/tests/test_utils.py
deleted file mode 100644
--- a/tests/test_utils.py
+++ /dev/null
@@ -1,61 +0,0 @@
-from functools import partial
-from typing import AsyncGenerator, Callable
-
-import pytest
-
-from litestar.utils.predicates import is_async_callable
-
-
-class AsyncTestCallable:
-    async def __call__(self, param1: int, param2: int) -> None:
-        ...
-
-    async def method(self, param1: int, param2: int) -> None:
-        ...
-
-
-async def async_generator() -> AsyncGenerator[int, None]:
-    yield 1
-
-
-class SyncTestCallable:
-    def __call__(self, param1: int, param2: int) -> None:
-        ...
-
-    def method(self, param1: int, param2: int) -> None:
-        ...
-
-
-async def async_func(param1: int, param2: int) -> None:
-    ...
-
-
-def sync_func(param1: int, param2: int) -> None:
-    ...
-
-
-async_callable = AsyncTestCallable()
-sync_callable = SyncTestCallable()
-
-
-@pytest.mark.parametrize(
-    "c, exp",
-    [
-        (async_callable, True),
-        (sync_callable, False),
-        (async_callable.method, True),
-        (sync_callable.method, False),
-        (async_func, True),
-        (sync_func, False),
-        (lambda: ..., False),
-        (AsyncTestCallable, True),
-        (SyncTestCallable, False),
-        (async_generator, False),
-    ],
-)
-def test_is_async_callable(c: Callable[[int, int], None], exp: bool) -> None:
-    assert is_async_callable(c) is exp
-    partial_1 = partial(c, 1)
-    assert is_async_callable(partial_1) is exp
-    partial_2 = partial(partial_1, 2)
-    assert is_async_callable(partial_2) is exp
diff --git a/tests/testing/__init__.py b/tests/testing/__init__.py
deleted file mode 100644
diff --git a/docs/examples/tests/security/__init__.py b/tests/unit/__init__.py
similarity index 100%
rename from docs/examples/tests/security/__init__.py
rename to tests/unit/__init__.py
diff --git a/tests/unit/test_app.py b/tests/unit/test_app.py
new file mode 100644
--- /dev/null
+++ b/tests/unit/test_app.py
@@ -0,0 +1,379 @@
+# ruff: noqa: UP006
+from __future__ import annotations
+
+import inspect
+import logging
+from dataclasses import fields
+from typing import TYPE_CHECKING, List, Tuple
+from unittest.mock import MagicMock, Mock, PropertyMock
+
+import pytest
+from pytest import MonkeyPatch
+
+from litestar import Litestar, MediaType, Request, Response, get, post
+from litestar.config.app import AppConfig
+from litestar.config.response_cache import ResponseCacheConfig
+from litestar.datastructures import MutableScopeHeaders, State
+from litestar.events.emitter import SimpleEventEmitter
+from litestar.exceptions import (
+    ImproperlyConfiguredException,
+    InternalServerException,
+    LitestarWarning,
+    NotFoundException,
+)
+from litestar.logging.config import LoggingConfig
+from litestar.router import Router
+from litestar.status_codes import HTTP_200_OK, HTTP_400_BAD_REQUEST, HTTP_500_INTERNAL_SERVER_ERROR
+from litestar.testing import TestClient, create_test_client
+from tests import Person
+
+if TYPE_CHECKING:
+    from typing import Dict
+
+    from litestar.types import Message, Scope
+
+
+@pytest.fixture()
+def app_config_object() -> AppConfig:
+    return AppConfig(
+        after_exception=[],
+        after_request=None,
+        after_response=None,
+        allowed_hosts=[],
+        before_request=None,
+        before_send=[],
+        response_cache_config=ResponseCacheConfig(),
+        cache_control=None,
+        compression_config=None,
+        cors_config=None,
+        csrf_config=None,
+        debug=False,
+        dependencies={},
+        etag=None,
+        event_emitter_backend=SimpleEventEmitter,
+        exception_handlers={},
+        guards=[],
+        listeners=[],
+        logging_config=None,
+        middleware=[],
+        multipart_form_part_limit=1000,
+        on_shutdown=[],
+        on_startup=[],
+        openapi_config=None,
+        opt={},
+        parameters={},
+        plugins=[],
+        request_class=None,
+        response_class=None,
+        response_cookies=[],
+        response_headers=[],
+        route_handlers=[],
+        security=[],
+        static_files_config=[],
+        tags=[],
+        template_config=None,
+        websocket_class=None,
+    )
+
+
+def test_access_openapi_schema_raises_if_not_configured() -> None:
+    """Test that accessing the openapi schema raises if not configured."""
+    app = Litestar(openapi_config=None)
+    with pytest.raises(ImproperlyConfiguredException):
+        app.openapi_schema
+
+
+def test_set_debug_updates_logging_level() -> None:
+    app = Litestar()
+
+    assert app.logger is not None
+    assert app.logger.level == logging.INFO  # type: ignore[attr-defined]
+
+    app.debug = True
+    assert app.logger.level == logging.DEBUG  # type: ignore[attr-defined]
+
+    app.debug = False
+    assert app.logger.level == logging.INFO  # type: ignore[attr-defined]
+
+
+@pytest.mark.parametrize("env_name,app_attr", [("LITESTAR_DEBUG", "debug"), ("LITESTAR_PDB", "pdb_on_exception")])
+@pytest.mark.parametrize(
+    "env_value,app_value,expected_value",
+    [
+        (None, None, False),
+        (None, False, False),
+        (None, True, True),
+        ("0", None, False),
+        ("0", False, False),
+        ("0", True, True),
+        ("1", None, True),
+        ("1", False, False),
+        ("1", True, True),
+    ],
+)
+def test_set_env_flags(
+    monkeypatch: MonkeyPatch,
+    env_value: str | None,
+    app_value: bool | None,
+    expected_value: bool,
+    env_name: str,
+    app_attr: str,
+) -> None:
+    if env_value is not None:
+        monkeypatch.setenv(env_name, env_value)
+    else:
+        monkeypatch.delenv(env_name, raising=False)
+
+    app = Litestar(**{app_attr: app_value})  # type: ignore[arg-type]
+
+    assert getattr(app, app_attr) is expected_value
+
+
+def test_warn_pdb_on_exception() -> None:
+    with pytest.warns(LitestarWarning, match="Debugger"):
+        Litestar(pdb_on_exception=True)
+
+
+def test_app_params_defined_on_app_config_object() -> None:
+    """Ensures that all parameters to the `Litestar` constructor are present on the `AppConfig` object."""
+    litestar_signature = inspect.signature(Litestar)
+    app_config_fields = {f.name for f in fields(AppConfig)}
+    for name in litestar_signature.parameters:
+        if name in {"on_app_init", "initial_state", "_preferred_validation_backend"}:
+            continue
+        assert name in app_config_fields
+    # ensure there are not fields defined on AppConfig that aren't in the Litestar signature
+    assert not (app_config_fields - set(litestar_signature.parameters.keys()))
+
+
+def test_app_config_object_used(app_config_object: AppConfig, monkeypatch: pytest.MonkeyPatch) -> None:
+    """Ensure that the properties on the `AppConfig` object are accessed within the `Litestar` constructor.
+
+    In the test we replace every field on the `AppConfig` type with a property mock so that we can check that it has at
+    least been accessed. It doesn't actually check that we do the right thing with it, but is a guard against the case
+    of adding a parameter to the `Litestar` signature and to the `AppConfig` object, and using the value from the
+    parameter downstream from construction of the `AppConfig` object.
+    """
+
+    # replace each field on the `AppConfig` object with a `PropertyMock`, this allows us to assert that the properties
+    # have been accessed during app instantiation.
+    property_mocks: List[Tuple[str, Mock]] = []
+    for field in fields(AppConfig):
+        if field.name == "response_cache_config":
+            property_mock = PropertyMock(return_value=ResponseCacheConfig())
+        if field.name in ["event_emitter_backend", "response_cache_config"]:
+            property_mock = PropertyMock(return_value=Mock())
+        else:
+            # default iterable return value allows the mock properties that need to be iterated over in
+            # `Litestar.__init__()` to not blow up, for other properties it shouldn't matter what the value is for the
+            # sake of this test.
+            property_mock = PropertyMock(return_value=[])
+        property_mocks.append((field.name, property_mock))
+        monkeypatch.setattr(type(app_config_object), field.name, property_mock, raising=False)
+
+    # Things that we don't actually need to call for this test
+    monkeypatch.setattr(Litestar, "register", MagicMock())
+    monkeypatch.setattr(Litestar, "_create_asgi_handler", MagicMock())
+    monkeypatch.setattr(Router, "__init__", MagicMock())
+
+    # instantiates the app with an `on_app_config` that returns our patched `AppConfig` object.
+    Litestar(on_app_init=[MagicMock(return_value=app_config_object)])
+
+    # this ensures that each of the properties of the `AppConfig` object have been accessed within `Litestar.__init__()`
+    for name, mock in property_mocks:
+        assert mock.called, f"expected {name} to be called"
+
+
+def test_app_debug_create_logger() -> None:
+    app = Litestar([], debug=True)
+
+    assert app.logging_config
+    assert app.logging_config.loggers["litestar"]["level"] == "DEBUG"  # type: ignore[attr-defined]
+
+
+def test_app_debug_explicitly_disable_logging() -> None:
+    app = Litestar([], debug=True, logging_config=None)
+
+    assert not app.logging_config
+
+
+def test_app_debug_update_logging_config() -> None:
+    logging_config = LoggingConfig()
+    app = Litestar([], debug=True, logging_config=logging_config)
+
+    assert app.logging_config is logging_config
+    assert app.logging_config.loggers["litestar"]["level"] == "DEBUG"  # type: ignore[attr-defined]
+
+
+def test_set_state() -> None:
+    def modify_state_in_hook(app_config: AppConfig) -> AppConfig:
+        assert isinstance(app_config.state, State)
+        app_config.state["c"] = "D"
+        app_config.state["e"] = "f"
+        return app_config
+
+    app = Litestar(state=State({"a": "b", "c": "d"}), on_app_init=[modify_state_in_hook])
+    assert app.state._state == {"a": "b", "c": "D", "e": "f"}
+
+
+def test_app_from_config(app_config_object: AppConfig) -> None:
+    Litestar.from_config(app_config_object)
+
+
+def test_before_send() -> None:
+    @get("/test")
+    def handler() -> Dict[str, str]:
+        return {"key": "value"}
+
+    async def before_send_hook_handler(message: Message, scope: Scope) -> None:
+        if message["type"] == "http.response.start":
+            headers = MutableScopeHeaders(message)
+            headers.add("My Header", scope["app"].state.message)
+
+    def on_startup(app: Litestar) -> None:
+        app.state.message = "value injected during send"
+
+    with create_test_client(handler, on_startup=[on_startup], before_send=[before_send_hook_handler]) as client:
+        response = client.get("/test")
+        assert response.status_code == HTTP_200_OK
+        assert response.headers.get("My Header") == "value injected during send"
+
+
+def test_default_handling_of_pydantic_errors() -> None:
+    @post("/{param:int}")
+    def my_route_handler(param: int, data: Person) -> None:
+        ...
+
+    with create_test_client(my_route_handler) as client:
+        response = client.post("/123", json={"first_name": "moishe"})
+        extra = response.json().get("extra")
+        assert extra is not None
+        assert len(extra) == 3
+
+
+def test_using_custom_http_exception_handler() -> None:
+    @get("/{param:int}")
+    def my_route_handler(param: int) -> None:
+        ...
+
+    def my_custom_handler(_: Request, __: Exception) -> Response:
+        return Response(content="custom message", media_type=MediaType.TEXT, status_code=HTTP_400_BAD_REQUEST)
+
+    with create_test_client(my_route_handler, exception_handlers={NotFoundException: my_custom_handler}) as client:
+        response = client.get("/abc")
+        assert response.text == "custom message"
+        assert response.status_code == HTTP_400_BAD_REQUEST
+
+
+def test_debug_response_created() -> None:
+    # this will test exception causes are recorded in output
+    # since frames include code in context we should not raise
+    # exception directly
+    def exception_thrower() -> float:
+        return 1 / 0
+
+    @get("/")
+    def my_route_handler() -> None:
+        try:
+            exception_thrower()
+        except Exception as e:
+            raise InternalServerException() from e
+
+    app = Litestar(route_handlers=[my_route_handler], debug=True)
+    client = TestClient(app=app)
+
+    response = client.get("/")
+    assert response.status_code == HTTP_500_INTERNAL_SERVER_ERROR
+    assert "text/plain" in response.headers["content-type"]
+
+    response = client.get("/", headers={"accept": "text/html"})
+    assert response.status_code == HTTP_500_INTERNAL_SERVER_ERROR
+    assert "text/html" in response.headers["content-type"]
+    assert "ZeroDivisionError" in response.text
+
+
+def test_handler_error_return_status_500() -> None:
+    @get("/")
+    def my_route_handler() -> None:
+        raise KeyError("custom message")
+
+    with create_test_client(my_route_handler) as client:
+        response = client.get("/")
+        assert response.status_code == HTTP_500_INTERNAL_SERVER_ERROR
+
+
+def test_lifespan() -> None:
+    events: list[str] = []
+    counter = {"value": 0}
+
+    def sync_function_without_app() -> None:
+        events.append("sync_function_without_app")
+        counter["value"] += 1
+
+    async def async_function_without_app() -> None:
+        events.append("async_function_without_app")
+        counter["value"] += 1
+
+    def sync_function_with_app(app: Litestar) -> None:
+        events.append("sync_function_with_app")
+        assert app is not None
+        assert isinstance(app.state, State)
+        counter["value"] += 1
+        app.state.x = True
+
+    async def async_function_with_app(app: Litestar) -> None:
+        events.append("async_function_with_app")
+        assert app is not None
+        assert isinstance(app.state, State)
+        counter["value"] += 1
+        app.state.y = True
+
+    with create_test_client(
+        [],
+        on_startup=[
+            sync_function_without_app,
+            async_function_without_app,
+            sync_function_with_app,
+            async_function_with_app,
+        ],
+        on_shutdown=[
+            sync_function_without_app,
+            async_function_without_app,
+            sync_function_with_app,
+            async_function_with_app,
+        ],
+    ) as client:
+        assert counter["value"] == 4
+        assert client.app.state.x
+        assert client.app.state.y
+        counter["value"] = 0
+        assert counter["value"] == 0
+    assert counter["value"] == 4
+    assert events == [
+        "sync_function_without_app",
+        "async_function_without_app",
+        "sync_function_with_app",
+        "async_function_with_app",
+        "sync_function_without_app",
+        "async_function_without_app",
+        "sync_function_with_app",
+        "async_function_with_app",
+    ]
+
+
+def test_registering_route_handler_generates_openapi_docs() -> None:
+    def fn() -> None:
+        return
+
+    app = Litestar(route_handlers=[])
+    assert app.openapi_schema
+
+    app.register(get("/path1")(fn))
+
+    paths = app.openapi_schema.paths
+
+    assert paths is not None
+    assert paths.get("/path1")
+
+    app.register(get("/path2")(fn))
+    assert paths.get("/path2")
diff --git a/tests/asgi_router/test_lifespan.py b/tests/unit/test_asgi_router.py
similarity index 92%
rename from tests/asgi_router/test_lifespan.py
rename to tests/unit/test_asgi_router.py
--- a/tests/asgi_router/test_lifespan.py
+++ b/tests/unit/test_asgi_router.py
@@ -4,17 +4,26 @@
 from typing import TYPE_CHECKING, AsyncGenerator, Callable
 from unittest.mock import AsyncMock, MagicMock
 
+import pytest
 from pytest_mock import MockerFixture
 
-from litestar import Litestar
+from litestar import Litestar, asgi
 from litestar._asgi.asgi_router import ASGIRouter
+from litestar.exceptions import ImproperlyConfiguredException
+from litestar.testing import TestClient, create_test_client
 
 if TYPE_CHECKING:
     from contextlib import AbstractAsyncContextManager
 
-import pytest
+    from litestar.types import Receive, Scope, Send
 
-from litestar.testing import TestClient, create_test_client
+
+def test_add_mount_route_disallow_path_parameter() -> None:
+    async def handler(scope: Scope, receive: Receive, send: Send) -> None:
+        return None
+
+    with pytest.raises(ImproperlyConfiguredException):
+        Litestar(route_handlers=[asgi("/mount-path", is_static=True)(handler), asgi("/mount-path/{id:str}")(handler)])
 
 
 class _LifeSpanCallable:
diff --git a/tests/datastructures/test_background_task.py b/tests/unit/test_background_tasks.py
similarity index 100%
rename from tests/datastructures/test_background_task.py
rename to tests/unit/test_background_tasks.py
diff --git a/tests/app/__init__.py b/tests/unit/test_channels/__init__.py
similarity index 100%
rename from tests/app/__init__.py
rename to tests/unit/test_channels/__init__.py
diff --git a/tests/channels/conftest.py b/tests/unit/test_channels/conftest.py
similarity index 61%
rename from tests/channels/conftest.py
rename to tests/unit/test_channels/conftest.py
--- a/tests/channels/conftest.py
+++ b/tests/unit/test_channels/conftest.py
@@ -1,29 +1,12 @@
 from __future__ import annotations
 
-from typing import AsyncGenerator
-
 import pytest
-from redis import Redis
 from redis.asyncio import Redis as AsyncRedis
 
 from litestar.channels.backends.memory import MemoryChannelsBackend
 from litestar.channels.backends.redis import RedisChannelsPubSubBackend, RedisChannelsStreamBackend
 
 
-@pytest.fixture()
-async def redis_client(docker_ip: str) -> AsyncGenerator[AsyncRedis, None]:
-    # this is to get around some weirdness with pytest-asyncio and redis interaction
-    # on 3.8 and 3.9
-
-    Redis(host=docker_ip, port=6397).flushall()
-    client: AsyncRedis = AsyncRedis(host=docker_ip, port=6397)
-    yield client
-    try:
-        await client.close()
-    except RuntimeError:
-        pass
-
-
 @pytest.fixture()
 def redis_stream_backend(redis_client: AsyncRedis) -> RedisChannelsStreamBackend:
     return RedisChannelsStreamBackend(history=10, redis=redis_client, cap_streams_approximate=False)
diff --git a/tests/channels/test_backends.py b/tests/unit/test_channels/test_backends.py
similarity index 94%
rename from tests/channels/test_backends.py
rename to tests/unit/test_channels/test_backends.py
--- a/tests/channels/test_backends.py
+++ b/tests/unit/test_channels/test_backends.py
@@ -1,7 +1,6 @@
 from __future__ import annotations
 
 import asyncio
-import sys
 from datetime import timedelta
 from typing import AsyncGenerator, cast
 
@@ -14,11 +13,6 @@
 from litestar.channels.backends.redis import RedisChannelsPubSubBackend, RedisChannelsStreamBackend
 from litestar.utils.compat import async_next
 
-pytestmark = [
-    pytest.mark.usefixtures("redis_service"),
-    pytest.mark.skipif(sys.platform != "linux", reason="docker not available on this platform"),
-]
-
 
 @pytest.fixture(
     params=[
@@ -96,7 +90,7 @@ async def test_get_history(
     assert history == expected_messages
 
 
-async def test_memory_backend_discards_history_entries(channels_backend: ChannelsBackend) -> None:
+async def test_discards_history_entries(channels_backend: ChannelsBackend) -> None:
     if isinstance(channels_backend, RedisChannelsPubSubBackend):
         pytest.skip()
 
diff --git a/tests/channels/test_plugin.py b/tests/unit/test_channels/test_plugin.py
similarity index 97%
rename from tests/channels/test_plugin.py
rename to tests/unit/test_channels/test_plugin.py
--- a/tests/channels/test_plugin.py
+++ b/tests/unit/test_channels/test_plugin.py
@@ -1,7 +1,6 @@
 from __future__ import annotations
 
 import asyncio
-import sys
 from secrets import token_hex
 from typing import cast
 from unittest.mock import AsyncMock, MagicMock
@@ -20,21 +19,6 @@
 
 from .util import get_from_stream
 
-pytestmark = [
-    pytest.mark.usefixtures("redis_service"),
-    pytest.mark.skipif(sys.platform != "linux", reason="docker not available on this platform"),
-]
-
-
-@pytest.fixture
-def mock() -> MagicMock:
-    return MagicMock()
-
-
-@pytest.fixture()
-def async_mock() -> AsyncMock:
-    return AsyncMock()
-
 
 @pytest.fixture(
     params=[
diff --git a/tests/channels/test_subscriber.py b/tests/unit/test_channels/test_subscriber.py
similarity index 100%
rename from tests/channels/test_subscriber.py
rename to tests/unit/test_channels/test_subscriber.py
diff --git a/tests/channels/util.py b/tests/unit/test_channels/util.py
similarity index 100%
rename from tests/channels/util.py
rename to tests/unit/test_channels/util.py
diff --git a/tests/cli/__init__.py b/tests/unit/test_cli/__init__.py
similarity index 100%
rename from tests/cli/__init__.py
rename to tests/unit/test_cli/__init__.py
diff --git a/tests/cli/conftest.py b/tests/unit/test_cli/conftest.py
similarity index 96%
rename from tests/cli/conftest.py
rename to tests/unit/test_cli/conftest.py
--- a/tests/cli/conftest.py
+++ b/tests/unit/test_cli/conftest.py
@@ -13,7 +13,8 @@
 from pytest_mock import MockerFixture
 
 from litestar.cli._utils import _path_to_dotted_path
-from tests.cli import (
+
+from . import (
     APP_FILE_CONTENT,
     CREATE_APP_FILE_CONTENT,
     GENERIC_APP_FACTORY_FILE_CONTENT,
@@ -116,6 +117,11 @@ def mock_uvicorn_run(mocker: MockerFixture) -> MagicMock:
     return mocker.patch("uvicorn.run")
 
 
+@pytest.fixture()
+def mock_subprocess_run(mocker: MockerFixture) -> MagicMock:
+    return mocker.patch("subprocess.run")
+
+
 @pytest.fixture
 def mock_confirm_ask(mocker: MockerFixture) -> Generator[MagicMock, None, None]:
     yield mocker.patch("rich.prompt.Confirm.ask", return_value=True)
diff --git a/tests/cli/test_cli.py b/tests/unit/test_cli/test_cli.py
similarity index 100%
rename from tests/cli/test_cli.py
rename to tests/unit/test_cli/test_cli.py
diff --git a/tests/cli/test_core_commands.py b/tests/unit/test_cli/test_core_commands.py
similarity index 95%
rename from tests/cli/test_core_commands.py
rename to tests/unit/test_cli/test_core_commands.py
--- a/tests/cli/test_core_commands.py
+++ b/tests/unit/test_cli/test_core_commands.py
@@ -12,26 +12,17 @@
 from litestar import __version__ as litestar_version
 from litestar.cli.main import litestar_group as cli_command
 from litestar.exceptions import LitestarWarning
-from tests.cli import (
+
+from . import (
     CREATE_APP_FILE_CONTENT,
     GENERIC_APP_FACTORY_FILE_CONTENT,
     GENERIC_APP_FACTORY_FILE_CONTENT_STRING_ANNOTATION,
 )
-from tests.cli.conftest import CreateAppFileFixture
+from .conftest import CreateAppFileFixture
 
 project_base = Path(__file__).parent.parent.parent
 
 
-@pytest.fixture()
-def mock_subprocess_run(mocker: MockerFixture) -> MagicMock:
-    return mocker.patch("litestar.cli.commands.core.subprocess.run")
-
-
-@pytest.fixture()
-def mock_uvicorn_run(mocker: MockerFixture) -> MagicMock:
-    return mocker.patch("litestar.cli.commands.core.uvicorn.run")
-
-
 @pytest.fixture()
 def mock_show_app_info(mocker: MockerFixture) -> MagicMock:
     return mocker.patch("litestar.cli.commands.core.show_app_info")
diff --git a/tests/cli/test_env_resolution.py b/tests/unit/test_cli/test_env_resolution.py
similarity index 98%
rename from tests/cli/test_env_resolution.py
rename to tests/unit/test_cli/test_env_resolution.py
--- a/tests/cli/test_env_resolution.py
+++ b/tests/unit/test_cli/test_env_resolution.py
@@ -7,7 +7,8 @@
 
 from litestar import Litestar
 from litestar.cli._utils import LitestarEnv, _path_to_dotted_path
-from tests.cli.conftest import CreateAppFileFixture
+
+from .conftest import CreateAppFileFixture
 
 
 @pytest.mark.parametrize("env_name,attr_name", [("LITESTAR_DEBUG", "debug"), ("LITESTAR_RELOAD", "reload")])
diff --git a/tests/cli/test_schema_commands.py b/tests/unit/test_cli/test_schema_commands.py
similarity index 88%
rename from tests/cli/test_schema_commands.py
rename to tests/unit/test_cli/test_schema_commands.py
--- a/tests/cli/test_schema_commands.py
+++ b/tests/unit/test_cli/test_schema_commands.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
 from json import dumps as json_dumps
 from typing import TYPE_CHECKING
 
@@ -14,7 +16,7 @@
 
 @pytest.mark.parametrize("filename", ("", "custom.json", "custom.yaml", "custom.yml"))
 def test_openapi_schema_command(
-    runner: "CliRunner", mocker: "MockerFixture", monkeypatch: "MonkeyPatch", filename: str
+    runner: CliRunner, mocker: MockerFixture, monkeypatch: MonkeyPatch, filename: str
 ) -> None:
     monkeypatch.setenv("LITESTAR_APP", "test_apps.openapi_test_app.main:app")
     mock_path_write_text = mocker.patch("pathlib.Path.write_text")
@@ -40,7 +42,7 @@ def test_openapi_schema_command(
     "namespace, filename", (("Custom", ""), ("", "custom_specs.ts"), ("Custom", "custom_specs.ts"))
 )
 def test_openapi_typescript_command(
-    runner: "CliRunner", mocker: "MockerFixture", monkeypatch: "MonkeyPatch", filename: str, namespace: str
+    runner: CliRunner, mocker: MockerFixture, monkeypatch: MonkeyPatch, filename: str, namespace: str
 ) -> None:
     monkeypatch.setenv("LITESTAR_APP", "test_apps.openapi_test_app.main:app")
     mock_path_write_text = mocker.patch("pathlib.Path.write_text")
diff --git a/tests/cli/test_session_commands.py b/tests/unit/test_cli/test_session_commands.py
similarity index 100%
rename from tests/cli/test_session_commands.py
rename to tests/unit/test_cli/test_session_commands.py
diff --git a/tests/asgi_router/__init__.py b/tests/unit/test_connection/__init__.py
similarity index 100%
rename from tests/asgi_router/__init__.py
rename to tests/unit/test_connection/__init__.py
diff --git a/tests/connection/test_base_properties.py b/tests/unit/test_connection/test_base.py
similarity index 100%
rename from tests/connection/test_base_properties.py
rename to tests/unit/test_connection/test_base.py
diff --git a/tests/connection/request/test_request.py b/tests/unit/test_connection/test_request.py
similarity index 94%
rename from tests/connection/request/test_request.py
rename to tests/unit/test_connection/test_request.py
--- a/tests/connection/request/test_request.py
+++ b/tests/unit/test_connection/test_request.py
@@ -9,11 +9,11 @@
 
 import pytest
 
-from litestar import MediaType, get
+from litestar import MediaType, Request, get
 from litestar.connection.base import empty_send
-from litestar.connection.request import Request
 from litestar.datastructures import Address, Cookie
 from litestar.exceptions import InternalServerException, SerializationException
+from litestar.middleware import MiddlewareProtocol
 from litestar.response.base import ASGIResponse
 from litestar.serialization import encode_json, encode_msgpack
 from litestar.static_files.config import StaticFilesConfig
@@ -22,7 +22,7 @@
 if TYPE_CHECKING:
     from pathlib import Path
 
-    from litestar.types import Receive, Scope, Send
+    from litestar.types import ASGIApp, Receive, Scope, Send
 
 
 async def test_request_empty_body_to_json(anyio_backend: str) -> None:
@@ -457,3 +457,28 @@ async def app(scope: "Scope", receive: "Receive", send: "Send") -> None:
     client = TestClient(app)
     response = client.get("/")
     assert response.json() == {"json": "Send channel not available"}
+
+
+class BeforeRequestMiddleWare(MiddlewareProtocol):
+    def __init__(self, app: "ASGIApp") -> None:
+        self.app = app
+
+    async def __call__(self, scope: "Scope", receive: "Receive", send: "Send") -> None:
+        scope["state"]["main"] = 1
+        await self.app(scope, receive, send)
+
+
+def test_state() -> None:
+    def before_request(request: Request) -> None:
+        assert request.state.main == 1
+        request.state.main = 2
+
+    @get(path="/")
+    async def get_state(request: Request) -> Dict[str, str]:
+        return {"state": request.state.main}
+
+    with create_test_client(
+        route_handlers=[get_state], middleware=[BeforeRequestMiddleWare], before_request=before_request
+    ) as client:
+        response = client.get("/")
+        assert response.json() == {"state": 2}
diff --git a/tests/connection/test_websocket.py b/tests/unit/test_connection/test_websocket.py
similarity index 62%
rename from tests/connection/test_websocket.py
rename to tests/unit/test_connection/test_websocket.py
--- a/tests/connection/test_websocket.py
+++ b/tests/unit/test_connection/test_websocket.py
@@ -85,52 +85,49 @@ async def handler(socket: MyWebSocket) -> None:
 
 def test_websocket_url() -> None:
     async def app(scope: Scope, receive: Receive, send: Send) -> None:
-        websocket = WebSocket[Any, Any, Any](scope, receive=receive, send=send)
-        await websocket.accept()
-        await websocket.send_json({"url": str(websocket.url)})
-        await websocket.close()
+        socket = WebSocket[Any, Any, Any](scope, receive=receive, send=send)
+        await socket.accept()
+        await socket.send_json({"url": str(socket.url)})
+        await socket.close()
 
-    with TestClient(app).websocket_connect("/123?a=abc") as websocket:
-        data = websocket.receive_json()
-        assert data == {"url": "ws://testserver/123?a=abc"}
+    with TestClient(app).websocket_connect("/123?a=abc") as ws:
+        assert ws.receive_json() == {"url": "ws://testserver/123?a=abc"}
 
 
 def test_websocket_binary_json() -> None:
     async def app(scope: Scope, receive: Receive, send: Send) -> None:
-        websocket = WebSocket[Any, Any, Any](scope, receive=receive, send=send)
-        await websocket.accept()
-        message = await websocket.receive_json(mode="binary")
-        await websocket.send_json(message, mode="binary")
-        await websocket.close()
+        socket = WebSocket[Any, Any, Any](scope, receive=receive, send=send)
+        await socket.accept()
+        message = await socket.receive_json(mode="binary")
+        await socket.send_json(message, mode="binary")
+        await socket.close()
 
-    with TestClient(app).websocket_connect("/123?a=abc") as websocket:
-        websocket.send_json({"test": "data"}, mode="binary")
-        data = websocket.receive_json(mode="binary")
-        assert data == {"test": "data"}
+    with TestClient(app).websocket_connect("/123?a=abc") as ws:
+        ws.send_json({"test": "data"}, mode="binary")
+        assert ws.receive_json(mode="binary") == {"test": "data"}
 
 
 def test_websocket_query_params() -> None:
     async def app(scope: Scope, receive: Receive, send: Send) -> None:
-        websocket = WebSocket[Any, Any, Any](scope, receive=receive, send=send)
-        query_params = dict(websocket.query_params)
-        await websocket.accept()
-        await websocket.send_json({"params": query_params})
-        await websocket.close()
+        socket = WebSocket[Any, Any, Any](scope, receive=receive, send=send)
+        query_params = dict(socket.query_params)
+        await socket.accept()
+        await socket.send_json({"params": query_params})
+        await socket.close()
 
-    with TestClient(app).websocket_connect("/?a=abc&b=456") as websocket:
-        data = websocket.receive_json()
-        assert data == {"params": {"a": "abc", "b": "456"}}
+    with TestClient(app).websocket_connect("/?a=abc&b=456") as ws:
+        assert ws.receive_json() == {"params": {"a": "abc", "b": "456"}}
 
 
 def test_websocket_headers() -> None:
     async def app(scope: Scope, receive: Receive, send: Send) -> None:
-        websocket = WebSocket[Any, Any, Any](scope, receive=receive, send=send)
-        headers = dict(websocket.headers)
-        await websocket.accept()
-        await websocket.send_json({"headers": headers})
-        await websocket.close()
+        socket = WebSocket[Any, Any, Any](scope, receive=receive, send=send)
+        headers = dict(socket.headers)
+        await socket.accept()
+        await socket.send_json({"headers": headers})
+        await socket.close()
 
-    with TestClient(app).websocket_connect("/") as websocket:
+    with TestClient(app).websocket_connect("/") as ws:
         expected_headers = {
             "accept": "*/*",
             "accept-encoding": "gzip, deflate, br",
@@ -140,62 +137,57 @@ async def app(scope: Scope, receive: Receive, send: Send) -> None:
             "sec-websocket-key": "testserver==",
             "sec-websocket-version": "13",
         }
-        data = websocket.receive_json()
-        assert data == {"headers": expected_headers}
+        assert ws.receive_json() == {"headers": expected_headers}
 
 
 def test_websocket_port() -> None:
     async def app(scope: Scope, receive: Receive, send: Send) -> None:
-        websocket = WebSocket[Any, Any, Any](scope, receive=receive, send=send)
-        await websocket.accept()
-        await websocket.send_json({"port": websocket.url.port})
-        await websocket.close()
+        socket = WebSocket[Any, Any, Any](scope, receive=receive, send=send)
+        await socket.accept()
+        await socket.send_json({"port": socket.url.port})
+        await socket.close()
 
-    with TestClient(app).websocket_connect("ws://example.com:123/123?a=abc") as websocket:
-        data = websocket.receive_json()
-        assert data == {"port": 123}
+    with TestClient(app).websocket_connect("ws://example.com:123/123?a=abc") as ws:
+        assert ws.receive_json() == {"port": 123}
 
 
 def test_websocket_send_and_receive_text() -> None:
     async def app(scope: Scope, receive: Receive, send: Send) -> None:
-        websocket = WebSocket[Any, Any, Any](scope, receive=receive, send=send)
-        await websocket.accept()
-        data = await websocket.receive_text()
-        await websocket.send_text("Message was: " + data)
-        await websocket.close()
+        socket = WebSocket[Any, Any, Any](scope, receive=receive, send=send)
+        await socket.accept()
+        data = await socket.receive_text()
+        await socket.send_text("Message was: " + data)
+        await socket.close()
 
-    with TestClient(app).websocket_connect("/") as websocket:
-        websocket.send_text("Hello, world!")
-        data = websocket.receive_text()
-        assert data == "Message was: Hello, world!"
+    with TestClient(app).websocket_connect("/") as ws:
+        ws.send_text("Hello, world!")
+        assert ws.receive_text() == "Message was: Hello, world!"
 
 
 def test_websocket_send_and_receive_bytes() -> None:
     async def app(scope: Scope, receive: Receive, send: Send) -> None:
-        websocket = WebSocket[Any, Any, Any](scope, receive=receive, send=send)
-        await websocket.accept()
-        data = await websocket.receive_bytes()
-        await websocket.send_bytes(b"Message was: " + data)
-        await websocket.close()
+        socket = WebSocket[Any, Any, Any](scope, receive=receive, send=send)
+        await socket.accept()
+        data = await socket.receive_bytes()
+        await socket.send_bytes(b"Message was: " + data)
+        await socket.close()
 
-    with TestClient(app).websocket_connect("/") as websocket:
-        websocket.send_bytes(b"Hello, world!")
-        data = websocket.receive_bytes()
-        assert data == b"Message was: Hello, world!"
+    with TestClient(app).websocket_connect("/") as ws:
+        ws.send_bytes(b"Hello, world!")
+        assert ws.receive_bytes() == b"Message was: Hello, world!"
 
 
 def test_websocket_send_and_receive_json() -> None:
     async def app(scope: Scope, receive: Receive, send: Send) -> None:
-        websocket = WebSocket[Any, Any, Any](scope, receive=receive, send=send)
-        await websocket.accept()
-        data = await websocket.receive_json()
-        await websocket.send_json({"message": data})
-        await websocket.close()
+        socket = WebSocket[Any, Any, Any](scope, receive=receive, send=send)
+        await socket.accept()
+        data = await socket.receive_json()
+        await socket.send_json({"message": data})
+        await socket.close()
 
-    with TestClient(app).websocket_connect("/") as websocket:
-        websocket.send_json({"hello": "world"})
-        data = websocket.receive_json()
-        assert data == {"message": {"hello": "world"}}
+    with TestClient(app).websocket_connect("/") as ws:
+        ws.send_json({"hello": "world"})
+        assert ws.receive_json() == {"message": {"hello": "world"}}
 
 
 def test_send_msgpack() -> None:
@@ -295,27 +287,27 @@ async def app(scope: Scope, receive: Receive, send: Send) -> None:
 def test_websocket_concurrency_pattern() -> None:
     stream_send, stream_receive = anyio.create_memory_object_stream()
 
-    async def reader(websocket: WebSocket[Any, Any, Any]) -> None:
+    async def reader(socket: WebSocket[Any, Any, Any]) -> None:
         async with stream_send:
-            data = await websocket.receive_json()
-            await stream_send.send(data)
+            json_data = await socket.receive_json()
+            await stream_send.send(json_data)
 
-    async def writer(websocket: WebSocket[Any, Any, Any]) -> None:
+    async def writer(socket: WebSocket[Any, Any, Any]) -> None:
         async with stream_receive:
             async for message in stream_receive:
-                await websocket.send_json(message)
+                await socket.send_json(message)
 
     async def app(scope: Scope, receive: Receive, send: Send) -> None:
-        websocket = WebSocket[Any, Any, Any](scope, receive=receive, send=send)
-        await websocket.accept()
+        socket = WebSocket[Any, Any, Any](scope, receive=receive, send=send)
+        await socket.accept()
         async with anyio.create_task_group() as task_group:
-            task_group.start_soon(reader, websocket)
-            await writer(websocket)
-        await websocket.close()
+            task_group.start_soon(reader, socket)
+            await writer(socket)
+        await socket.close()
 
-    with TestClient(app).websocket_connect("/") as websocket:
-        websocket.send_json({"hello": "world"})
-        data = websocket.receive_json()
+    with TestClient(app).websocket_connect("/") as ws:
+        ws.send_json({"hello": "world"})
+        data = ws.receive_json()
         assert data == {"hello": "world"}
 
 
@@ -324,33 +316,33 @@ def test_client_close() -> None:
 
     async def app(scope: Scope, receive: Receive, send: Send) -> None:
         nonlocal close_code
-        websocket = WebSocket[Any, Any, Any](scope, receive=receive, send=send)
-        await websocket.accept()
+        socket = WebSocket[Any, Any, Any](scope, receive=receive, send=send)
+        await socket.accept()
         try:
-            await websocket.receive_text()
+            await socket.receive_text()
         except WebSocketException as exc:
             close_code = exc.code
 
-    with TestClient(app).websocket_connect("/") as websocket:
-        websocket.close(code=WS_1001_GOING_AWAY)
+    with TestClient(app).websocket_connect("/") as ws:
+        ws.close(code=WS_1001_GOING_AWAY)
     assert close_code == WS_1001_GOING_AWAY
 
 
 def test_application_close() -> None:
     async def app(scope: Scope, receive: Receive, send: Send) -> None:
-        websocket = WebSocket[Any, Any, Any](scope, receive=receive, send=send)
-        await websocket.accept()
-        await websocket.close(WS_1001_GOING_AWAY)
+        socket = WebSocket[Any, Any, Any](scope, receive=receive, send=send)
+        await socket.accept()
+        await socket.close(WS_1001_GOING_AWAY)
 
-    with TestClient(app).websocket_connect("/") as websocket, pytest.raises(WebSocketDisconnect) as exc:
-        websocket.receive_text()
+    with TestClient(app).websocket_connect("/") as ws, pytest.raises(WebSocketDisconnect) as exc:
+        ws.receive_text()
     assert exc.value.code == WS_1001_GOING_AWAY
 
 
 def test_rejected_connection() -> None:
     async def app(scope: Scope, receive: Receive, send: Send) -> None:
-        websocket = WebSocket[Any, Any, Any](scope, receive=receive, send=send)
-        await websocket.close(WS_1001_GOING_AWAY)
+        socket = WebSocket[Any, Any, Any](scope, receive=receive, send=send)
+        await socket.close(WS_1001_GOING_AWAY)
 
     with pytest.raises(WebSocketDisconnect) as exc, TestClient(app).websocket_connect("/"):
         pass
@@ -359,20 +351,20 @@ async def app(scope: Scope, receive: Receive, send: Send) -> None:
 
 def test_subprotocol() -> None:
     async def app(scope: Scope, receive: Receive, send: Send) -> None:
-        websocket = WebSocket[Any, Any, Any](scope, receive=receive, send=send)
-        assert websocket.scope["subprotocols"] == ["soap", "wamp"]
-        await websocket.accept(subprotocols="wamp")
-        await websocket.close()
+        socket = WebSocket[Any, Any, Any](scope, receive=receive, send=send)
+        assert socket.scope["subprotocols"] == ["soap", "wamp"]
+        await socket.accept(subprotocols="wamp")
+        await socket.close()
 
-    with TestClient(app).websocket_connect("/", subprotocols=["soap", "wamp"]) as websocket:
-        assert websocket.accepted_subprotocol == "wamp"
+    with TestClient(app).websocket_connect("/", subprotocols=["soap", "wamp"]) as ws:
+        assert ws.accepted_subprotocol == "wamp"
 
 
 def test_additional_headers() -> None:
     async def app(scope: Scope, receive: Receive, send: Send) -> None:
-        websocket = WebSocket[Any, Any, Any](scope, receive=receive, send=send)
-        await websocket.accept(headers=[(b"additional", b"header")])
-        await websocket.close()
+        socket = WebSocket[Any, Any, Any](scope, receive=receive, send=send)
+        await socket.accept(headers=[(b"additional", b"header")])
+        await socket.close()
 
     with TestClient(app).websocket_connect("/") as websocket:
         assert websocket.extra_headers == [(b"additional", b"header")]
@@ -380,12 +372,12 @@ async def app(scope: Scope, receive: Receive, send: Send) -> None:
 
 def test_no_additional_headers() -> None:
     async def app(scope: Scope, receive: Receive, send: Send) -> None:
-        websocket = WebSocket[Any, Any, Any](scope, receive=receive, send=send)
-        await websocket.accept()
-        await websocket.close()
+        socket = WebSocket[Any, Any, Any](scope, receive=receive, send=send)
+        await socket.accept()
+        await socket.close()
 
-    with TestClient(app).websocket_connect("/") as websocket:
-        assert websocket.extra_headers == []
+    with TestClient(app).websocket_connect("/") as ws:
+        assert ws.extra_headers == []
 
 
 def test_websocket_exception() -> None:
@@ -398,11 +390,11 @@ async def app(scope: Scope, receive: Receive, send: Send) -> None:
 
 def test_duplicate_disconnect() -> None:
     async def app(scope: Scope, receive: Receive, send: Send) -> None:
-        websocket = WebSocket[Any, Any, Any](scope, receive=receive, send=send)
-        await websocket.accept()
-        message = await websocket.receive()
+        socket = WebSocket[Any, Any, Any](scope, receive=receive, send=send)
+        await socket.accept()
+        message = await socket.receive()
         assert message["type"] == "websocket.disconnect"
-        message = await websocket.receive()
+        await socket.receive()
 
     with pytest.raises(WebSocketException), TestClient(app).websocket_connect("/") as websocket:
         websocket.close()
@@ -410,20 +402,20 @@ async def app(scope: Scope, receive: Receive, send: Send) -> None:
 
 def test_websocket_close_reason() -> None:
     async def app(scope: Scope, receive: Receive, send: Send) -> None:
-        websocket = WebSocket[Any, Any, Any](scope, receive=receive, send=send)
-        await websocket.accept()
-        await websocket.close(code=WS_1001_GOING_AWAY, reason="Going Away")
+        socket = WebSocket[Any, Any, Any](scope, receive=receive, send=send)
+        await socket.accept()
+        await socket.close(code=WS_1001_GOING_AWAY, reason="Going Away")
 
-    with TestClient(app).websocket_connect("/") as websocket, pytest.raises(WebSocketDisconnect) as exc:
-        websocket.receive_text()
+    with TestClient(app).websocket_connect("/") as ws, pytest.raises(WebSocketDisconnect) as exc:
+        ws.receive_text()
         assert exc.value.code == WS_1001_GOING_AWAY
         assert exc.value.detail == "Going Away"
 
 
 def test_receive_text_before_accept() -> None:
     async def app(scope: Scope, receive: Receive, send: Send) -> None:
-        websocket = WebSocket[Any, Any, Any](scope, receive=receive, send=send)
-        await websocket.receive_text()
+        socket = WebSocket[Any, Any, Any](scope, receive=receive, send=send)
+        await socket.receive_text()
 
     with pytest.raises(WebSocketException), TestClient(app).websocket_connect("/"):
         pass
@@ -431,8 +423,8 @@ async def app(scope: Scope, receive: Receive, send: Send) -> None:
 
 def test_receive_bytes_before_accept() -> None:
     async def app(scope: Scope, receive: Receive, send: Send) -> None:
-        websocket = WebSocket[Any, Any, Any](scope, receive=receive, send=send)
-        await websocket.receive_bytes()
+        socket = WebSocket[Any, Any, Any](scope, receive=receive, send=send)
+        await socket.receive_bytes()
 
     with pytest.raises(WebSocketException), TestClient(app).websocket_connect("/"):
         pass
@@ -440,8 +432,8 @@ async def app(scope: Scope, receive: Receive, send: Send) -> None:
 
 def test_receive_json_before_accept() -> None:
     async def app(scope: Scope, receive: Receive, send: Send) -> None:
-        websocket = WebSocket[Any, Any, Any](scope, receive=receive, send=send)
-        await websocket.receive_json()
+        socket = WebSocket[Any, Any, Any](scope, receive=receive, send=send)
+        await socket.receive_json()
 
     with pytest.raises(WebSocketException), TestClient(app).websocket_connect("/"):
         pass
diff --git a/tests/asgi_router/routing_trie/__init__.py b/tests/unit/test_contrib/__init__.py
similarity index 100%
rename from tests/asgi_router/routing_trie/__init__.py
rename to tests/unit/test_contrib/__init__.py
diff --git a/tests/contrib/conftest.py b/tests/unit/test_contrib/conftest.py
similarity index 100%
rename from tests/contrib/conftest.py
rename to tests/unit/test_contrib/conftest.py
diff --git a/tests/channels/__init__.py b/tests/unit/test_contrib/test_htmx/__init__.py
similarity index 100%
rename from tests/channels/__init__.py
rename to tests/unit/test_contrib/test_htmx/__init__.py
diff --git a/tests/contrib/htmx/test_htmx_request.py b/tests/unit/test_contrib/test_htmx/test_htmx_request.py
similarity index 100%
rename from tests/contrib/htmx/test_htmx_request.py
rename to tests/unit/test_contrib/test_htmx/test_htmx_request.py
diff --git a/tests/contrib/htmx/test_htmx_response.py b/tests/unit/test_contrib/test_htmx/test_htmx_response.py
similarity index 94%
rename from tests/contrib/htmx/test_htmx_response.py
rename to tests/unit/test_contrib/test_htmx/test_htmx_response.py
--- a/tests/contrib/htmx/test_htmx_response.py
+++ b/tests/unit/test_contrib/test_htmx/test_htmx_response.py
@@ -245,8 +245,8 @@ def handler() -> HXLocation:
         ),
     ),
 )
-def test_HTMXTemplate_response_success(engine: Any, template: str, expected: str, template_dir: Path) -> None:
-    Path(template_dir / "abc.html").write_text(template)
+def test_HTMXTemplate_response_success(engine: Any, template: str, expected: str, tmp_path: Path) -> None:
+    Path(tmp_path / "abc.html").write_text(template)
 
     @get(path="/")
     def handler() -> HTMXTemplate:
@@ -264,7 +264,7 @@ def handler() -> HTMXTemplate:
     with create_test_client(
         route_handlers=[handler],
         template_config=TemplateConfig(
-            directory=template_dir,
+            directory=tmp_path,
             engine=engine,
         ),
     ) as client:
@@ -283,8 +283,8 @@ def handler() -> HTMXTemplate:
         (MakoTemplateEngine, "path: ${request.scope['path']}", "path: /"),
     ),
 )
-def test_HTMXTemplate_response_no_params(engine: Any, template: str, expected: str, template_dir: Path) -> None:
-    Path(template_dir / "abc.html").write_text(template)
+def test_HTMXTemplate_response_no_params(engine: Any, template: str, expected: str, tmp_path: Path) -> None:
+    Path(tmp_path / "abc.html").write_text(template)
 
     @get(path="/")
     def handler() -> HTMXTemplate:
@@ -296,7 +296,7 @@ def handler() -> HTMXTemplate:
     with create_test_client(
         route_handlers=[handler],
         template_config=TemplateConfig(
-            directory=template_dir,
+            directory=tmp_path,
             engine=engine,
         ),
     ) as client:
@@ -315,10 +315,8 @@ def handler() -> HTMXTemplate:
         (MakoTemplateEngine, "path: ${request.scope['path']}", "path: /"),
     ),
 )
-def test_HTMXTemplate_response_push_url_set_to_false(
-    engine: Any, template: str, expected: str, template_dir: Path
-) -> None:
-    Path(template_dir / "abc.html").write_text(template)
+def test_HTMXTemplate_response_push_url_set_to_false(engine: Any, template: str, expected: str, tmp_path: Path) -> None:
+    Path(tmp_path / "abc.html").write_text(template)
 
     @get(path="/")
     def handler() -> HTMXTemplate:
@@ -331,7 +329,7 @@ def handler() -> HTMXTemplate:
     with create_test_client(
         route_handlers=[handler],
         template_config=TemplateConfig(
-            directory=template_dir,
+            directory=tmp_path,
             engine=engine,
         ),
     ) as client:
@@ -350,10 +348,8 @@ def handler() -> HTMXTemplate:
         (MakoTemplateEngine, "path: ${request.scope['path']}", "path: /"),
     ),
 )
-def test_htmx_template_response_bad_trigger_params(
-    engine: Any, template: str, expected: str, template_dir: Path
-) -> None:
-    Path(template_dir / "abc.html").write_text(template)
+def test_htmx_template_response_bad_trigger_params(engine: Any, template: str, expected: str, tmp_path: Path) -> None:
+    Path(tmp_path / "abc.html").write_text(template)
 
     @get(path="/")
     def handler() -> HTMXTemplate:
@@ -368,7 +364,7 @@ def handler() -> HTMXTemplate:
     with create_test_client(
         route_handlers=[handler],
         template_config=TemplateConfig(
-            directory=template_dir,
+            directory=tmp_path,
             engine=engine,
         ),
     ) as client:
diff --git a/tests/compatibility/__init__.py b/tests/unit/test_contrib/test_jwt/__init__.py
similarity index 100%
rename from tests/compatibility/__init__.py
rename to tests/unit/test_contrib/test_jwt/__init__.py
diff --git a/tests/contrib/jwt/test_auth.py b/tests/unit/test_contrib/test_jwt/test_auth.py
similarity index 99%
rename from tests/contrib/jwt/test_auth.py
rename to tests/unit/test_contrib/test_jwt/test_auth.py
--- a/tests/contrib/jwt/test_auth.py
+++ b/tests/unit/test_contrib/test_jwt/test_auth.py
@@ -11,12 +11,17 @@
 from litestar import Litestar, Request, Response, get
 from litestar.contrib.jwt import JWTAuth, JWTCookieAuth, OAuth2PasswordBearerAuth, Token
 from litestar.status_codes import HTTP_200_OK, HTTP_201_CREATED, HTTP_401_UNAUTHORIZED
+from litestar.stores.memory import MemoryStore
 from litestar.testing import create_test_client
 from tests import User, UserFactory
 
 if TYPE_CHECKING:
     from litestar.connection import ASGIConnection
-    from litestar.stores.memory import MemoryStore
+
+
+@pytest.fixture(scope="module")
+def mock_db() -> MemoryStore:
+    return MemoryStore()
 
 
 @given(
diff --git a/tests/contrib/jwt/test_token.py b/tests/unit/test_contrib/test_jwt/test_token.py
similarity index 100%
rename from tests/contrib/jwt/test_token.py
rename to tests/unit/test_contrib/test_jwt/test_token.py
diff --git a/tests/contrib/test_msgspec.py b/tests/unit/test_contrib/test_msgspec.py
similarity index 92%
rename from tests/contrib/test_msgspec.py
rename to tests/unit/test_contrib/test_msgspec.py
--- a/tests/contrib/test_msgspec.py
+++ b/tests/unit/test_contrib/test_msgspec.py
@@ -27,7 +27,7 @@ class TestStruct(Struct):
     field_defs = list(MsgspecDTO.generate_field_definitions(TestStruct))
     assert (
         field_defs[0].unique_model_name
-        == "tests.contrib.test_msgspec.test_field_definition_generation.<locals>.TestStruct"
+        == "tests.unit.test_contrib.test_msgspec.test_field_definition_generation.<locals>.TestStruct"
     )
     for field_def, exp in zip(field_defs, expected_field_defs):
         assert field_def == exp
diff --git a/tests/contrib/open_telemetry/test_open_telemetry_middleware.py b/tests/unit/test_contrib/test_opentelemetry.py
similarity index 100%
rename from tests/contrib/open_telemetry/test_open_telemetry_middleware.py
rename to tests/unit/test_contrib/test_opentelemetry.py
diff --git a/tests/contrib/test_pydantic.py b/tests/unit/test_contrib/test_pydantic.py
similarity index 95%
rename from tests/contrib/test_pydantic.py
rename to tests/unit/test_contrib/test_pydantic.py
--- a/tests/contrib/test_pydantic.py
+++ b/tests/unit/test_contrib/test_pydantic.py
@@ -28,7 +28,7 @@ class TestModel(BaseModel):
     field_defs = list(PydanticDTO.generate_field_definitions(TestModel))
     assert (
         field_defs[0].unique_model_name
-        == "tests.contrib.test_pydantic.test_field_definition_generation.<locals>.TestModel"
+        == "tests.unit.test_contrib.test_pydantic.test_field_definition_generation.<locals>.TestModel"
     )
     for field_def, exp in zip(field_defs, expected_field_defs):
         assert field_def == exp
diff --git a/tests/contrib/repository/test_handlers.py b/tests/unit/test_contrib/test_repository.py
similarity index 100%
rename from tests/contrib/repository/test_handlers.py
rename to tests/unit/test_contrib/test_repository.py
diff --git a/tests/connection/__init__.py b/tests/unit/test_contrib/test_sqlalchemy/__init__.py
similarity index 100%
rename from tests/connection/__init__.py
rename to tests/unit/test_contrib/test_sqlalchemy/__init__.py
diff --git a/tests/contrib/sqlalchemy/models_bigint.py b/tests/unit/test_contrib/test_sqlalchemy/models_bigint.py
similarity index 100%
rename from tests/contrib/sqlalchemy/models_bigint.py
rename to tests/unit/test_contrib/test_sqlalchemy/models_bigint.py
diff --git a/tests/contrib/sqlalchemy/models_uuid.py b/tests/unit/test_contrib/test_sqlalchemy/models_uuid.py
similarity index 100%
rename from tests/contrib/sqlalchemy/models_uuid.py
rename to tests/unit/test_contrib/test_sqlalchemy/models_uuid.py
diff --git a/tests/contrib/sqlalchemy/test_dto.py b/tests/unit/test_contrib/test_sqlalchemy/test_dto.py
similarity index 100%
rename from tests/contrib/sqlalchemy/test_dto.py
rename to tests/unit/test_contrib/test_sqlalchemy/test_dto.py
diff --git a/tests/contrib/sqlalchemy/test_dto_integration.py b/tests/unit/test_contrib/test_sqlalchemy/test_dto_integration.py
similarity index 100%
rename from tests/contrib/sqlalchemy/test_dto_integration.py
rename to tests/unit/test_contrib/test_sqlalchemy/test_dto_integration.py
diff --git a/tests/contrib/__init__.py b/tests/unit/test_contrib/test_sqlalchemy/test_init_plugin/__init__.py
similarity index 100%
rename from tests/contrib/__init__.py
rename to tests/unit/test_contrib/test_sqlalchemy/test_init_plugin/__init__.py
diff --git a/tests/contrib/sqlalchemy/init_plugin/config/test_asyncio.py b/tests/unit/test_contrib/test_sqlalchemy/test_init_plugin/test_asyncio.py
similarity index 100%
rename from tests/contrib/sqlalchemy/init_plugin/config/test_asyncio.py
rename to tests/unit/test_contrib/test_sqlalchemy/test_init_plugin/test_asyncio.py
diff --git a/tests/contrib/sqlalchemy/init_plugin/config/test_common.py b/tests/unit/test_contrib/test_sqlalchemy/test_init_plugin/test_common.py
similarity index 100%
rename from tests/contrib/sqlalchemy/init_plugin/config/test_common.py
rename to tests/unit/test_contrib/test_sqlalchemy/test_init_plugin/test_common.py
diff --git a/tests/contrib/sqlalchemy/init_plugin/config/test_engine.py b/tests/unit/test_contrib/test_sqlalchemy/test_init_plugin/test_engine.py
similarity index 100%
rename from tests/contrib/sqlalchemy/init_plugin/config/test_engine.py
rename to tests/unit/test_contrib/test_sqlalchemy/test_init_plugin/test_engine.py
diff --git a/tests/contrib/sqlalchemy/init_plugin/config/test_sync.py b/tests/unit/test_contrib/test_sqlalchemy/test_init_plugin/test_sync.py
similarity index 100%
rename from tests/contrib/sqlalchemy/init_plugin/config/test_sync.py
rename to tests/unit/test_contrib/test_sqlalchemy/test_init_plugin/test_sync.py
diff --git a/tests/contrib/htmx/__init__.py b/tests/unit/test_contrib/test_sqlalchemy/test_repository/__init__.py
similarity index 100%
rename from tests/contrib/htmx/__init__.py
rename to tests/unit/test_contrib/test_sqlalchemy/test_repository/__init__.py
diff --git a/tests/contrib/sqlalchemy/repository/conftest.py b/tests/unit/test_contrib/test_sqlalchemy/test_repository/conftest.py
similarity index 97%
rename from tests/contrib/sqlalchemy/repository/conftest.py
rename to tests/unit/test_contrib/test_sqlalchemy/test_repository/conftest.py
--- a/tests/contrib/sqlalchemy/repository/conftest.py
+++ b/tests/unit/test_contrib/test_sqlalchemy/test_repository/conftest.py
@@ -12,8 +12,6 @@
 from sqlalchemy.ext.asyncio import AsyncEngine, AsyncSession, async_sessionmaker, create_async_engine
 from sqlalchemy.orm import Session, sessionmaker
 
-from tests.contrib.sqlalchemy.repository.helpers import mark_requires_docker
-
 if TYPE_CHECKING:
     from pytest import MonkeyPatch
 
@@ -283,8 +281,8 @@ def spanner_engine(docker_ip: str, spanner_service: None, monkeypatch: MonkeyPat
 @pytest.fixture(
     params=[
         pytest.param("duckdb_engine", marks=[pytest.mark.sqlalchemy_duckdb, pytest.mark.sqlalchemy_integration]),
-        pytest.param("oracle_engine", marks=[pytest.mark.sqlalchemy_oracledb, *mark_requires_docker]),
-        pytest.param("psycopg_engine", marks=[pytest.mark.sqlalchemy_psycopg_sync, *mark_requires_docker]),
+        pytest.param("oracle_engine", marks=[pytest.mark.sqlalchemy_oracledb, pytest.mark.sqlalchemy_integration]),
+        pytest.param("psycopg_engine", marks=[pytest.mark.sqlalchemy_psycopg_sync, pytest.mark.sqlalchemy_integration]),
         pytest.param("sqlite_engine", marks=pytest.mark.sqlalchemy_sqlite),
     ]
 )
@@ -391,9 +389,11 @@ async def psycopg_async_engine(docker_ip: str, postgres_service: None) -> AsyncE
 @pytest.fixture(
     params=[
         pytest.param("aiosqlite_engine", marks=pytest.mark.sqlalchemy_aiosqlite),
-        pytest.param("asyncmy_engine", marks=[pytest.mark.sqlalchemy_asyncmy, *mark_requires_docker]),
-        pytest.param("asyncpg_engine", marks=[pytest.mark.sqlalchemy_asyncpg, *mark_requires_docker]),
-        pytest.param("psycopg_async_engine", marks=[pytest.mark.sqlalchemy_psycopg_async, *mark_requires_docker]),
+        pytest.param("asyncmy_engine", marks=[pytest.mark.sqlalchemy_asyncmy, pytest.mark.sqlalchemy_integration]),
+        pytest.param("asyncpg_engine", marks=[pytest.mark.sqlalchemy_asyncpg, pytest.mark.sqlalchemy_integration]),
+        pytest.param(
+            "psycopg_async_engine", marks=[pytest.mark.sqlalchemy_psycopg_async, pytest.mark.sqlalchemy_integration]
+        ),
     ]
 )
 def async_engine(request: FixtureRequest) -> AsyncEngine:
diff --git a/tests/contrib/sqlalchemy/repository/helpers.py b/tests/unit/test_contrib/test_sqlalchemy/test_repository/helpers.py
similarity index 86%
rename from tests/contrib/sqlalchemy/repository/helpers.py
rename to tests/unit/test_contrib/test_sqlalchemy/test_repository/helpers.py
--- a/tests/contrib/sqlalchemy/repository/helpers.py
+++ b/tests/unit/test_contrib/test_sqlalchemy/test_repository/helpers.py
@@ -1,12 +1,9 @@
 from __future__ import annotations
 
 import inspect
-import sys
 from datetime import datetime, timezone
 from typing import Any, Awaitable, TypeVar, cast, overload
 
-import pytest
-
 T = TypeVar("T")
 
 
@@ -38,9 +35,3 @@ def update_raw_records(raw_authors: list[dict[str, Any]], raw_rules: list[dict[s
     for raw_rule in raw_rules:
         raw_rule["created_at"] = datetime.strptime(raw_rule["created_at"], "%Y-%m-%dT%H:%M:%S").astimezone(timezone.utc)
         raw_rule["updated_at"] = datetime.strptime(raw_rule["updated_at"], "%Y-%m-%dT%H:%M:%S").astimezone(timezone.utc)
-
-
-mark_requires_docker = [
-    pytest.mark.sqlalchemy_integration,
-    pytest.mark.skipif(sys.platform != "linux", reason="docker not available on this platform"),
-]
diff --git a/tests/contrib/sqlalchemy/repository/test_abc.py b/tests/unit/test_contrib/test_sqlalchemy/test_repository/test_abc.py
similarity index 100%
rename from tests/contrib/sqlalchemy/repository/test_abc.py
rename to tests/unit/test_contrib/test_sqlalchemy/test_repository/test_abc.py
diff --git a/tests/contrib/sqlalchemy/repository/test_generic_mock_async_repository.py b/tests/unit/test_contrib/test_sqlalchemy/test_repository/test_generic_mock_async_repository.py
similarity index 99%
rename from tests/contrib/sqlalchemy/repository/test_generic_mock_async_repository.py
rename to tests/unit/test_contrib/test_sqlalchemy/test_repository/test_generic_mock_async_repository.py
--- a/tests/contrib/sqlalchemy/repository/test_generic_mock_async_repository.py
+++ b/tests/unit/test_contrib/test_sqlalchemy/test_repository/test_generic_mock_async_repository.py
@@ -7,11 +7,9 @@
 from sqlalchemy.orm import Mapped, mapped_column
 
 from litestar.contrib.repository.exceptions import ConflictError, RepositoryError
-from litestar.contrib.repository.testing.generic_mock_repository import (
-    GenericAsyncMockRepository,
-)
+from litestar.contrib.repository.testing.generic_mock_repository import GenericAsyncMockRepository
 from litestar.contrib.sqlalchemy import base
-from tests.contrib.sqlalchemy.models_uuid import UUIDAuthor, UUIDBook
+from tests.unit.test_contrib.test_sqlalchemy.models_uuid import UUIDAuthor, UUIDBook
 
 
 @pytest.fixture(name="authors")
diff --git a/tests/contrib/sqlalchemy/repository/test_generic_mock_sync_repository.py b/tests/unit/test_contrib/test_sqlalchemy/test_repository/test_generic_mock_sync_repository.py
similarity index 99%
rename from tests/contrib/sqlalchemy/repository/test_generic_mock_sync_repository.py
rename to tests/unit/test_contrib/test_sqlalchemy/test_repository/test_generic_mock_sync_repository.py
--- a/tests/contrib/sqlalchemy/repository/test_generic_mock_sync_repository.py
+++ b/tests/unit/test_contrib/test_sqlalchemy/test_repository/test_generic_mock_sync_repository.py
@@ -11,7 +11,7 @@
     GenericSyncMockRepository,
 )
 from litestar.contrib.sqlalchemy import base
-from tests.contrib.sqlalchemy.models_uuid import UUIDAuthor, UUIDBook
+from tests.unit.test_contrib.test_sqlalchemy.models_uuid import UUIDAuthor, UUIDBook
 
 
 @pytest.fixture(name="authors")
diff --git a/tests/contrib/sqlalchemy/repository/test_repo_bigint.py b/tests/unit/test_contrib/test_sqlalchemy/test_repository/test_repo_bigint.py
similarity index 99%
rename from tests/contrib/sqlalchemy/repository/test_repo_bigint.py
rename to tests/unit/test_contrib/test_sqlalchemy/test_repository/test_repo_bigint.py
--- a/tests/contrib/sqlalchemy/repository/test_repo_bigint.py
+++ b/tests/unit/test_contrib/test_sqlalchemy/test_repository/test_repo_bigint.py
@@ -14,7 +14,7 @@
 from litestar.contrib.repository.exceptions import RepositoryError
 from litestar.contrib.repository.filters import BeforeAfter, CollectionFilter, OrderBy, SearchFilter
 from litestar.contrib.sqlalchemy import base
-from tests.contrib.sqlalchemy.models_bigint import (
+from tests.unit.test_contrib.test_sqlalchemy.models_bigint import (
     AuthorAsyncRepository,
     AuthorSyncRepository,
     BigIntAuthor,
@@ -25,7 +25,8 @@
     RuleAsyncRepository,
     RuleSyncRepository,
 )
-from tests.contrib.sqlalchemy.repository.helpers import maybe_async, update_raw_records
+
+from .helpers import maybe_async, update_raw_records
 
 
 @pytest.fixture()
diff --git a/tests/contrib/sqlalchemy/repository/test_repo_uuid.py b/tests/unit/test_contrib/test_sqlalchemy/test_repository/test_repo_uuid.py
similarity index 98%
rename from tests/contrib/sqlalchemy/repository/test_repo_uuid.py
rename to tests/unit/test_contrib/test_sqlalchemy/test_repository/test_repo_uuid.py
--- a/tests/contrib/sqlalchemy/repository/test_repo_uuid.py
+++ b/tests/unit/test_contrib/test_sqlalchemy/test_repository/test_repo_uuid.py
@@ -19,7 +19,7 @@
 from litestar.contrib.repository.exceptions import RepositoryError
 from litestar.contrib.repository.filters import BeforeAfter, CollectionFilter, OrderBy, SearchFilter
 from litestar.contrib.sqlalchemy import base
-from tests.contrib.sqlalchemy.models_uuid import (
+from tests.unit.test_contrib.test_sqlalchemy.models_uuid import (
     AuthorAsyncRepository,
     AuthorSyncRepository,
     BookAsyncRepository,
@@ -31,16 +31,16 @@
     UUIDRule,
 )
 
-from .helpers import mark_requires_docker, maybe_async, update_raw_records
+from .helpers import maybe_async, update_raw_records
 
 
 @pytest.fixture(
     params=[
         pytest.param("sqlite_engine", marks=pytest.mark.sqlalchemy_sqlite),
-        pytest.param("duckdb_engine", marks=[pytest.mark.sqlalchemy_duckdb, *mark_requires_docker]),
-        pytest.param("oracle_engine", marks=[pytest.mark.sqlalchemy_oracledb, *mark_requires_docker]),
-        pytest.param("psycopg_engine", marks=[pytest.mark.sqlalchemy_psycopg_sync, *mark_requires_docker]),
-        pytest.param("spanner_engine", marks=[pytest.mark.sqlalchemy_spanner, *mark_requires_docker]),
+        pytest.param("duckdb_engine", marks=[pytest.mark.sqlalchemy_duckdb, pytest.mark.sqlalchemy_integration]),
+        pytest.param("oracle_engine", marks=[pytest.mark.sqlalchemy_oracledb, pytest.mark.sqlalchemy_integration]),
+        pytest.param("psycopg_engine", marks=[pytest.mark.sqlalchemy_psycopg_sync, pytest.mark.sqlalchemy_integration]),
+        pytest.param("spanner_engine", marks=[pytest.mark.sqlalchemy_spanner, pytest.mark.sqlalchemy_integration]),
     ]
 )
 def engine(request: FixtureRequest) -> Engine:
diff --git a/tests/contrib/sqlalchemy/repository/test_sqlalchemy_async.py b/tests/unit/test_contrib/test_sqlalchemy/test_repository/test_sqlalchemy_async.py
similarity index 100%
rename from tests/contrib/sqlalchemy/repository/test_sqlalchemy_async.py
rename to tests/unit/test_contrib/test_sqlalchemy/test_repository/test_sqlalchemy_async.py
diff --git a/tests/contrib/sqlalchemy/repository/test_sqlalchemy_oracledb_json.py b/tests/unit/test_contrib/test_sqlalchemy/test_repository/test_sqlalchemy_oracledb_json.py
similarity index 77%
rename from tests/contrib/sqlalchemy/repository/test_sqlalchemy_oracledb_json.py
rename to tests/unit/test_contrib/test_sqlalchemy/test_repository/test_sqlalchemy_oracledb_json.py
--- a/tests/contrib/sqlalchemy/repository/test_sqlalchemy_oracledb_json.py
+++ b/tests/unit/test_contrib/test_sqlalchemy/test_repository/test_sqlalchemy_oracledb_json.py
@@ -2,19 +2,16 @@
 from __future__ import annotations
 
 import platform
-import sys
 
 import pytest
 from sqlalchemy import Engine
 from sqlalchemy.dialects import oracle
 from sqlalchemy.schema import CreateTable
 
-from tests.contrib.sqlalchemy.models_uuid import UUIDEventLog
+from tests.unit.test_contrib.test_sqlalchemy.models_uuid import UUIDEventLog
 
 pytestmark = [
-    pytest.mark.skipif(sys.platform != "linux", reason="docker not available on this platform"),
     pytest.mark.skipif(platform.uname()[4] != "x86_64", reason="oracle not available on this platform"),
-    pytest.mark.sqlalchemy_integration,
 ]
 
 
diff --git a/tests/contrib/sqlalchemy/repository/test_sqlalchemy_sync.py b/tests/unit/test_contrib/test_sqlalchemy/test_repository/test_sqlalchemy_sync.py
similarity index 100%
rename from tests/contrib/sqlalchemy/repository/test_sqlalchemy_sync.py
rename to tests/unit/test_contrib/test_sqlalchemy/test_repository/test_sqlalchemy_sync.py
diff --git a/tests/contrib/sqlalchemy/test_serialization_plugin.py b/tests/unit/test_contrib/test_sqlalchemy/test_serialization_plugin.py
similarity index 100%
rename from tests/contrib/sqlalchemy/test_serialization_plugin.py
rename to tests/unit/test_contrib/test_sqlalchemy/test_serialization_plugin.py
diff --git a/tests/test_controller.py b/tests/unit/test_controller.py
similarity index 100%
rename from tests/test_controller.py
rename to tests/unit/test_controller.py
diff --git a/tests/test_data_extractors.py b/tests/unit/test_data_extractors.py
similarity index 100%
rename from tests/test_data_extractors.py
rename to tests/unit/test_data_extractors.py
diff --git a/tests/datastructures/__init_.py b/tests/unit/test_datastructures/__init_.py
similarity index 100%
rename from tests/datastructures/__init_.py
rename to tests/unit/test_datastructures/__init_.py
diff --git a/tests/datastructures/test_cookie.py b/tests/unit/test_datastructures/test_cookie.py
similarity index 100%
rename from tests/datastructures/test_cookie.py
rename to tests/unit/test_datastructures/test_cookie.py
diff --git a/tests/datastructures/test_headers.py b/tests/unit/test_datastructures/test_headers.py
similarity index 100%
rename from tests/datastructures/test_headers.py
rename to tests/unit/test_datastructures/test_headers.py
diff --git a/tests/datastructures/test_multi_dicts.py b/tests/unit/test_datastructures/test_multi_dicts.py
similarity index 100%
rename from tests/datastructures/test_multi_dicts.py
rename to tests/unit/test_datastructures/test_multi_dicts.py
diff --git a/tests/unit/test_datastructures/test_response_header.py b/tests/unit/test_datastructures/test_response_header.py
new file mode 100644
--- /dev/null
+++ b/tests/unit/test_datastructures/test_response_header.py
@@ -0,0 +1,10 @@
+import pytest
+
+from litestar.datastructures import ResponseHeader
+from litestar.exceptions import ImproperlyConfiguredException
+
+
+def test_response_headers_validation() -> None:
+    ResponseHeader(name="test", documentation_only=True)
+    with pytest.raises(ImproperlyConfiguredException):
+        ResponseHeader(name="test")
diff --git a/tests/datastructures/test_state.py b/tests/unit/test_datastructures/test_state.py
similarity index 100%
rename from tests/datastructures/test_state.py
rename to tests/unit/test_datastructures/test_state.py
diff --git a/tests/datastructures/test_upload_file.py b/tests/unit/test_datastructures/test_upload_file.py
similarity index 100%
rename from tests/datastructures/test_upload_file.py
rename to tests/unit/test_datastructures/test_upload_file.py
diff --git a/tests/datastructures/test_url.py b/tests/unit/test_datastructures/test_url.py
similarity index 100%
rename from tests/datastructures/test_url.py
rename to tests/unit/test_datastructures/test_url.py
diff --git a/tests/unit/test_di.py b/tests/unit/test_di.py
new file mode 100644
--- /dev/null
+++ b/tests/unit/test_di.py
@@ -0,0 +1,147 @@
+from functools import partial
+from typing import Any, AsyncGenerator, Generator
+
+import pytest
+
+from litestar.di import Provide
+from litestar.exceptions import ImproperlyConfiguredException, LitestarWarning
+from litestar.types import Empty
+
+
+def generator_func() -> Generator[float, None, None]:
+    yield 0.1
+
+
+async def async_generator_func() -> AsyncGenerator[float, None]:
+    yield 0.1
+
+
+async def async_callable(val: str = "three-one") -> str:
+    return val
+
+
+def sync_callable(val: str = "three-one") -> str:
+    return val
+
+
+async_partial = partial(async_callable, "why-three-and-one")
+sync_partial = partial(sync_callable, "why-three-and-one")
+
+
+class C:
+    val = 31
+
+    def __init__(self) -> None:
+        self.val = 13
+
+    @classmethod
+    async def async_class(cls) -> int:
+        return cls.val
+
+    @classmethod
+    def sync_class(cls) -> int:
+        return cls.val
+
+    @staticmethod
+    async def async_static() -> str:
+        return "one-three"
+
+    @staticmethod
+    def sync_static() -> str:
+        return "one-three"
+
+    async def async_instance(self) -> int:
+        return self.val
+
+    def sync_instance(self) -> int:
+        return self.val
+
+
+async def test_provide_default(anyio_backend: str) -> None:
+    provider = Provide(dependency=async_callable)
+    value = await provider()
+    assert value == "three-one"
+
+
+async def test_provide_cached(anyio_backend: str) -> None:
+    provider = Provide(dependency=async_callable, use_cache=True)
+    assert provider.value is Empty
+    value = await provider()
+    assert value == "three-one"
+    assert provider.value == value
+    second_value = await provider()
+    assert value == second_value
+    third_value = await provider()
+    assert value == third_value
+
+
+async def test_run_in_thread(anyio_backend: str) -> None:
+    provider = Provide(dependency=sync_callable, sync_to_thread=True)
+    value = await provider()
+    assert value == "three-one"
+
+
+def test_provider_equality_check() -> None:
+    first_provider = Provide(dependency=sync_callable, sync_to_thread=False)
+    second_provider = Provide(dependency=sync_callable, sync_to_thread=False)
+    assert first_provider == second_provider
+    third_provider = Provide(dependency=sync_callable, use_cache=True, sync_to_thread=False)
+    assert first_provider != third_provider
+    second_provider.value = True
+    assert first_provider != second_provider
+
+
+@pytest.mark.parametrize(
+    "fn, exp",
+    [
+        (C.async_class, 31),
+        (C.sync_class, 31),
+        (C.async_static, "one-three"),
+        (C.sync_static, "one-three"),
+        (C().async_instance, 13),
+        (C().sync_instance, 13),
+        (async_callable, "three-one"),
+        (sync_callable, "three-one"),
+        (async_partial, "why-three-and-one"),
+        (sync_partial, "why-three-and-one"),
+    ],
+)
+@pytest.mark.usefixtures("disable_warn_sync_to_thread_with_async")
+async def test_provide_for_callable(fn: Any, exp: Any, anyio_backend: str) -> None:
+    assert await Provide(fn, sync_to_thread=False)() == exp
+
+
+@pytest.mark.usefixtures("enable_warn_implicit_sync_to_thread")
+def test_sync_callable_without_sync_to_thread_warns() -> None:
+    def func() -> None:
+        pass
+
+    with pytest.warns(LitestarWarning, match="discouraged since synchronous callables"):
+        Provide(func)
+
+
+@pytest.mark.parametrize("sync_to_thread", [True, False])
+def test_async_callable_with_sync_to_thread_warns(sync_to_thread: bool) -> None:
+    async def func() -> None:
+        pass
+
+    with pytest.warns(LitestarWarning, match="asynchronous callable"):
+        Provide(func, sync_to_thread=sync_to_thread)
+
+
+@pytest.mark.parametrize(
+    ("dep", "exp"),
+    [
+        (sync_callable, True),
+        (async_callable, False),
+        (generator_func, True),
+        (async_generator_func, True),
+    ],
+)
+def test_dependency_has_async_callable(dep: Any, exp: bool) -> None:
+    assert Provide(dep).has_sync_callable is exp
+
+
+def test_raises_when_dependency_is_not_callable() -> None:
+    with pytest.raises(ImproperlyConfiguredException):
+        Provide(123)  # type: ignore
diff --git a/tests/dto/__init__.py b/tests/unit/test_dto/__init__.py
similarity index 100%
rename from tests/dto/__init__.py
rename to tests/unit/test_dto/__init__.py
diff --git a/tests/dto/test_attrs_fail.py b/tests/unit/test_dto/test_attrs_fail.py
similarity index 93%
rename from tests/dto/test_attrs_fail.py
rename to tests/unit/test_dto/test_attrs_fail.py
--- a/tests/dto/test_attrs_fail.py
+++ b/tests/unit/test_dto/test_attrs_fail.py
@@ -4,7 +4,8 @@
 
 from litestar import post
 from litestar.testing import create_test_client
-from tests.dto import MockDTO, Model
+
+from . import MockDTO, Model
 
 
 @pytest.mark.xfail
diff --git a/tests/dto/factory/__init__.py b/tests/unit/test_dto/test_factory/__init__.py
similarity index 100%
rename from tests/dto/factory/__init__.py
rename to tests/unit/test_dto/test_factory/__init__.py
diff --git a/tests/dto/factory/test_abc.py b/tests/unit/test_dto/test_factory/test_abc.py
similarity index 100%
rename from tests/dto/factory/test_abc.py
rename to tests/unit/test_dto/test_factory/test_abc.py
diff --git a/tests/contrib/jwt/__init__.py b/tests/unit/test_dto/test_factory/test_backends/__init__.py
similarity index 100%
rename from tests/contrib/jwt/__init__.py
rename to tests/unit/test_dto/test_factory/test_backends/__init__.py
diff --git a/tests/dto/factory/backends/test_abc.py b/tests/unit/test_dto/test_factory/test_backends/test_abc.py
similarity index 100%
rename from tests/dto/factory/backends/test_abc.py
rename to tests/unit/test_dto/test_factory/test_backends/test_abc.py
diff --git a/tests/dto/factory/backends/test_backends.py b/tests/unit/test_dto/test_factory/test_backends/test_backends.py
similarity index 100%
rename from tests/dto/factory/backends/test_backends.py
rename to tests/unit/test_dto/test_factory/test_backends/test_backends.py
diff --git a/tests/dto/factory/backends/test_utils.py b/tests/unit/test_dto/test_factory/test_backends/test_utils.py
similarity index 100%
rename from tests/dto/factory/backends/test_utils.py
rename to tests/unit/test_dto/test_factory/test_backends/test_utils.py
diff --git a/tests/dto/factory/test_integration.py b/tests/unit/test_dto/test_factory/test_integration.py
similarity index 99%
rename from tests/dto/factory/test_integration.py
rename to tests/unit/test_dto/test_factory/test_integration.py
--- a/tests/dto/factory/test_integration.py
+++ b/tests/unit/test_dto/test_factory/test_integration.py
@@ -278,7 +278,9 @@ def handler(data: Bar) -> Bar:
         assert len(schemas) == 2
         assert schemas[0] != schemas[1]
         assert all(
-            k.startswith("tests.dto.factory.test_integration.test_dto_openapi_model_name_collision.<locals>.Bar")
+            k.startswith(
+                "tests.unit.test_dto.test_factory.test_integration.test_dto_openapi_model_name_collision.<locals>.Bar"
+            )
             for k in response.json()["components"]["schemas"]
         )
 
diff --git a/tests/dto/factory/test_stdlib.py b/tests/unit/test_dto/test_factory/test_stdlib.py
similarity index 100%
rename from tests/dto/factory/test_stdlib.py
rename to tests/unit/test_dto/test_factory/test_stdlib.py
diff --git a/tests/dto/factory/test_utils.py b/tests/unit/test_dto/test_factory/test_utils.py
similarity index 100%
rename from tests/dto/factory/test_utils.py
rename to tests/unit/test_dto/test_factory/test_utils.py
diff --git a/tests/dto/test_integration.py b/tests/unit/test_dto/test_integration.py
similarity index 98%
rename from tests/dto/test_integration.py
rename to tests/unit/test_dto/test_integration.py
--- a/tests/dto/test_integration.py
+++ b/tests/unit/test_dto/test_integration.py
@@ -5,7 +5,8 @@
 
 from litestar import Controller, Router, post
 from litestar.testing import create_test_client
-from tests.dto import MockDTO, MockReturnDTO, Model
+
+from . import MockDTO, MockReturnDTO, Model
 
 
 def test_dto_defined_on_handler() -> None:
diff --git a/tests/dto/test_interface.py b/tests/unit/test_dto/test_interface.py
similarity index 100%
rename from tests/dto/test_interface.py
rename to tests/unit/test_dto/test_interface.py
diff --git a/tests/events/test_listener.py b/tests/unit/test_events.py
similarity index 100%
rename from tests/events/test_listener.py
rename to tests/unit/test_events.py
diff --git a/tests/test_exceptions.py b/tests/unit/test_exceptions.py
similarity index 100%
rename from tests/test_exceptions.py
rename to tests/unit/test_exceptions.py
diff --git a/tests/test_file_system.py b/tests/unit/test_file_system.py
similarity index 100%
rename from tests/test_file_system.py
rename to tests/unit/test_file_system.py
diff --git a/tests/test_guards.py b/tests/unit/test_guards.py
similarity index 100%
rename from tests/test_guards.py
rename to tests/unit/test_guards.py
diff --git a/tests/contrib/open_telemetry/__init__.py b/tests/unit/test_handlers/__init__.py
similarity index 100%
rename from tests/contrib/open_telemetry/__init__.py
rename to tests/unit/test_handlers/__init__.py
diff --git a/tests/contrib/sqlalchemy/__init__.py b/tests/unit/test_handlers/test_asgi_handlers/__init__.py
similarity index 100%
rename from tests/contrib/sqlalchemy/__init__.py
rename to tests/unit/test_handlers/test_asgi_handlers/__init__.py
diff --git a/tests/handlers/asgi/test_handle_asgi.py b/tests/unit/test_handlers/test_asgi_handlers/test_handle_asgi.py
similarity index 100%
rename from tests/handlers/asgi/test_handle_asgi.py
rename to tests/unit/test_handlers/test_asgi_handlers/test_handle_asgi.py
diff --git a/tests/handlers/asgi/test_handle_asgi_with_future_annotations.py b/tests/unit/test_handlers/test_asgi_handlers/test_handle_asgi_with_future_annotations.py
similarity index 100%
rename from tests/handlers/asgi/test_handle_asgi_with_future_annotations.py
rename to tests/unit/test_handlers/test_asgi_handlers/test_handle_asgi_with_future_annotations.py
diff --git a/tests/handlers/asgi/test_validations.py b/tests/unit/test_handlers/test_asgi_handlers/test_validations.py
similarity index 100%
rename from tests/handlers/asgi/test_validations.py
rename to tests/unit/test_handlers/test_asgi_handlers/test_validations.py
diff --git a/tests/contrib/sqlalchemy/init_plugin/__init__.py b/tests/unit/test_handlers/test_base_handlers/__init__.py
similarity index 100%
rename from tests/contrib/sqlalchemy/init_plugin/__init__.py
rename to tests/unit/test_handlers/test_base_handlers/__init__.py
diff --git a/tests/handlers/base/test_opt.py b/tests/unit/test_handlers/test_base_handlers/test_opt.py
similarity index 100%
rename from tests/handlers/base/test_opt.py
rename to tests/unit/test_handlers/test_base_handlers/test_opt.py
diff --git a/tests/handlers/base/test_resolution.py b/tests/unit/test_handlers/test_base_handlers/test_resolution.py
similarity index 100%
rename from tests/handlers/base/test_resolution.py
rename to tests/unit/test_handlers/test_base_handlers/test_resolution.py
diff --git a/tests/handlers/base/test_validations.py b/tests/unit/test_handlers/test_base_handlers/test_validations.py
similarity index 100%
rename from tests/handlers/base/test_validations.py
rename to tests/unit/test_handlers/test_base_handlers/test_validations.py
diff --git a/tests/contrib/sqlalchemy/init_plugin/config/__init__.py b/tests/unit/test_handlers/test_http_handlers/__init__.py
similarity index 100%
rename from tests/contrib/sqlalchemy/init_plugin/config/__init__.py
rename to tests/unit/test_handlers/test_http_handlers/__init__.py
diff --git a/tests/handlers/http/test_defaults.py b/tests/unit/test_handlers/test_http_handlers/test_defaults.py
similarity index 100%
rename from tests/handlers/http/test_defaults.py
rename to tests/unit/test_handlers/test_http_handlers/test_defaults.py
diff --git a/tests/handlers/http/test_delete.py b/tests/unit/test_handlers/test_http_handlers/test_delete.py
similarity index 100%
rename from tests/handlers/http/test_delete.py
rename to tests/unit/test_handlers/test_http_handlers/test_delete.py
diff --git a/tests/handlers/http/test_head.py b/tests/unit/test_handlers/test_http_handlers/test_head.py
similarity index 100%
rename from tests/handlers/http/test_head.py
rename to tests/unit/test_handlers/test_http_handlers/test_head.py
diff --git a/tests/handlers/http/test_kwarg_handling.py b/tests/unit/test_handlers/test_http_handlers/test_kwarg_handling.py
similarity index 100%
rename from tests/handlers/http/test_kwarg_handling.py
rename to tests/unit/test_handlers/test_http_handlers/test_kwarg_handling.py
diff --git a/tests/handlers/http/test_media_type.py b/tests/unit/test_handlers/test_http_handlers/test_media_type.py
similarity index 100%
rename from tests/handlers/http/test_media_type.py
rename to tests/unit/test_handlers/test_http_handlers/test_media_type.py
diff --git a/tests/handlers/http/test_signature_namespace.py b/tests/unit/test_handlers/test_http_handlers/test_signature_namespace.py
similarity index 100%
rename from tests/handlers/http/test_signature_namespace.py
rename to tests/unit/test_handlers/test_http_handlers/test_signature_namespace.py
diff --git a/tests/handlers/http/test_sync.py b/tests/unit/test_handlers/test_http_handlers/test_sync.py
similarity index 100%
rename from tests/handlers/http/test_sync.py
rename to tests/unit/test_handlers/test_http_handlers/test_sync.py
diff --git a/tests/handlers/http/test_to_response.py b/tests/unit/test_handlers/test_http_handlers/test_to_response.py
similarity index 100%
rename from tests/handlers/http/test_to_response.py
rename to tests/unit/test_handlers/test_http_handlers/test_to_response.py
diff --git a/tests/handlers/http/test_validations.py b/tests/unit/test_handlers/test_http_handlers/test_validations.py
similarity index 100%
rename from tests/handlers/http/test_validations.py
rename to tests/unit/test_handlers/test_http_handlers/test_validations.py
diff --git a/tests/contrib/sqlalchemy/repository/__init__.py b/tests/unit/test_handlers/test_websocket_handlers/__init__.py
similarity index 100%
rename from tests/contrib/sqlalchemy/repository/__init__.py
rename to tests/unit/test_handlers/test_websocket_handlers/__init__.py
diff --git a/tests/handlers/websocket/test_handle_websocket.py b/tests/unit/test_handlers/test_websocket_handlers/test_handle_websocket.py
similarity index 100%
rename from tests/handlers/websocket/test_handle_websocket.py
rename to tests/unit/test_handlers/test_websocket_handlers/test_handle_websocket.py
diff --git a/tests/handlers/websocket/test_handle_websocket_with_future_annotations.py b/tests/unit/test_handlers/test_websocket_handlers/test_handle_websocket_with_future_annotations.py
similarity index 100%
rename from tests/handlers/websocket/test_handle_websocket_with_future_annotations.py
rename to tests/unit/test_handlers/test_websocket_handlers/test_handle_websocket_with_future_annotations.py
diff --git a/tests/handlers/websocket/test_kwarg_handling.py b/tests/unit/test_handlers/test_websocket_handlers/test_kwarg_handling.py
similarity index 100%
rename from tests/handlers/websocket/test_kwarg_handling.py
rename to tests/unit/test_handlers/test_websocket_handlers/test_kwarg_handling.py
diff --git a/tests/handlers/websocket/test_listeners.py b/tests/unit/test_handlers/test_websocket_handlers/test_listeners.py
similarity index 99%
rename from tests/handlers/websocket/test_listeners.py
rename to tests/unit/test_handlers/test_websocket_handlers/test_listeners.py
--- a/tests/handlers/websocket/test_listeners.py
+++ b/tests/unit/test_handlers/test_websocket_handlers/test_listeners.py
@@ -17,11 +17,6 @@
 from litestar.types.asgi_types import WebSocketMode
 
 
-@pytest.fixture
-def mock() -> MagicMock:
-    return MagicMock()
-
-
 @pytest.fixture
 def listener_class(mock: MagicMock) -> Type[WebsocketListener]:
     class Listener(WebsocketListener):
diff --git a/tests/handlers/websocket/test_validations.py b/tests/unit/test_handlers/test_websocket_handlers/test_validations.py
similarity index 100%
rename from tests/handlers/websocket/test_validations.py
rename to tests/unit/test_handlers/test_websocket_handlers/test_validations.py
diff --git a/tests/kwargs/__init__.py b/tests/unit/test_kwargs/__init__.py
similarity index 100%
rename from tests/kwargs/__init__.py
rename to tests/unit/test_kwargs/__init__.py
diff --git a/tests/kwargs/flower.jpeg b/tests/unit/test_kwargs/flower.jpeg
similarity index 100%
rename from tests/kwargs/flower.jpeg
rename to tests/unit/test_kwargs/flower.jpeg
diff --git a/tests/kwargs/test_attrs_data.py b/tests/unit/test_kwargs/test_attrs_data.py
similarity index 100%
rename from tests/kwargs/test_attrs_data.py
rename to tests/unit/test_kwargs/test_attrs_data.py
diff --git a/tests/unit/test_kwargs/test_cleanup_group.py b/tests/unit/test_kwargs/test_cleanup_group.py
new file mode 100644
--- /dev/null
+++ b/tests/unit/test_kwargs/test_cleanup_group.py
@@ -0,0 +1,91 @@
+from typing import AsyncGenerator, Generator
+from unittest.mock import MagicMock
+
+import pytest
+
+from litestar._kwargs.cleanup import DependencyCleanupGroup
+from litestar.utils.compat import async_next
+
+
+@pytest.fixture
+def cleanup_mock() -> MagicMock:
+    return MagicMock()
+
+
+@pytest.fixture
+def async_cleanup_mock() -> MagicMock:
+    return MagicMock()
+
+
+@pytest.fixture
+def generator(cleanup_mock: MagicMock) -> Generator[str, None, None]:
+    def func() -> Generator[str, None, None]:
+        yield "hello"
+        cleanup_mock()
+
+    return func()
+
+
+@pytest.fixture
+def async_generator(async_cleanup_mock: MagicMock) -> AsyncGenerator[str, None]:
+    async def func() -> AsyncGenerator[str, None]:
+        yield "world"
+        async_cleanup_mock()
+
+    return func()
+
+
+def test_add(generator: Generator[str, None, None]) -> None:
+    group = DependencyCleanupGroup()
+
+    group.add(generator)
+
+    assert group._generators == [generator]
+
+
+async def test_cleanup(generator: Generator[str, None, None], cleanup_mock: MagicMock) -> None:
+    next(generator)
+    group = DependencyCleanupGroup([generator])
+
+    await group.cleanup()
+
+    cleanup_mock.assert_called_once()
+    assert group._closed
+
+
+async def test_cleanup_multiple(
+    generator: Generator[str, None, None],
+    async_generator: AsyncGenerator[str, None],
+    cleanup_mock: MagicMock,
+    async_cleanup_mock: MagicMock,
+) -> None:
+    next(generator)
+    await async_next(async_generator)
+    group = DependencyCleanupGroup([generator, async_generator])
+
+    await group.cleanup()
+
+    cleanup_mock.assert_called_once()
+    async_cleanup_mock.assert_called_once()
+    assert group._closed
+
+
+async def test_cleanup_on_closed_raises(generator: Generator[str, None, None]) -> None:
+    next(generator)
+    group = DependencyCleanupGroup([generator])
+
+    await group.cleanup()
+    with pytest.raises(RuntimeError):
+        await group.cleanup()
+
+
+async def test_add_on_closed_raises(
+    generator: Generator[str, None, None], async_generator: AsyncGenerator[str, None]
+) -> None:
+    next(generator)
+    group = DependencyCleanupGroup([generator])
+
+    await group.cleanup()
+
+    with pytest.raises(RuntimeError):
+        group.add(async_generator)
diff --git a/tests/kwargs/test_cookie_params.py b/tests/unit/test_kwargs/test_cookie_params.py
similarity index 100%
rename from tests/kwargs/test_cookie_params.py
rename to tests/unit/test_kwargs/test_cookie_params.py
diff --git a/tests/kwargs/test_defaults.py b/tests/unit/test_kwargs/test_defaults.py
similarity index 100%
rename from tests/kwargs/test_defaults.py
rename to tests/unit/test_kwargs/test_defaults.py
diff --git a/tests/kwargs/test_dependency_batches.py b/tests/unit/test_kwargs/test_dependency_batches.py
similarity index 100%
rename from tests/kwargs/test_dependency_batches.py
rename to tests/unit/test_kwargs/test_dependency_batches.py
diff --git a/tests/kwargs/test_dto_extractor.py b/tests/unit/test_kwargs/test_dto_extractor.py
similarity index 86%
rename from tests/kwargs/test_dto_extractor.py
rename to tests/unit/test_kwargs/test_dto_extractor.py
--- a/tests/kwargs/test_dto_extractor.py
+++ b/tests/unit/test_kwargs/test_dto_extractor.py
@@ -3,7 +3,7 @@
 from unittest.mock import AsyncMock
 
 from litestar._kwargs.extractors import create_dto_extractor
-from tests.dto import MockDTO, Model
+from tests.unit.test_dto import MockDTO, Model
 
 
 async def test_create_dto_extractor() -> None:
diff --git a/tests/kwargs/test_generator_dependencies.py b/tests/unit/test_kwargs/test_generator_dependencies.py
similarity index 100%
rename from tests/kwargs/test_generator_dependencies.py
rename to tests/unit/test_kwargs/test_generator_dependencies.py
diff --git a/tests/kwargs/test_header_params.py b/tests/unit/test_kwargs/test_header_params.py
similarity index 100%
rename from tests/kwargs/test_header_params.py
rename to tests/unit/test_kwargs/test_header_params.py
diff --git a/tests/kwargs/test_json_data.py b/tests/unit/test_kwargs/test_json_data.py
similarity index 96%
rename from tests/kwargs/test_json_data.py
rename to tests/unit/test_kwargs/test_json_data.py
--- a/tests/kwargs/test_json_data.py
+++ b/tests/unit/test_kwargs/test_json_data.py
@@ -2,7 +2,8 @@
 from litestar.params import Body
 from litestar.status_codes import HTTP_201_CREATED
 from litestar.testing import create_test_client
-from tests.kwargs import Form
+
+from . import Form
 
 
 def test_request_body_json() -> None:
diff --git a/tests/kwargs/test_layered_params.py b/tests/unit/test_kwargs/test_layered_params.py
similarity index 100%
rename from tests/kwargs/test_layered_params.py
rename to tests/unit/test_kwargs/test_layered_params.py
diff --git a/tests/kwargs/test_msgpack_data.py b/tests/unit/test_kwargs/test_msgpack_data.py
similarity index 100%
rename from tests/kwargs/test_msgpack_data.py
rename to tests/unit/test_kwargs/test_msgpack_data.py
diff --git a/tests/kwargs/test_multipart_data.py b/tests/unit/test_kwargs/test_multipart_data.py
similarity index 99%
rename from tests/kwargs/test_multipart_data.py
rename to tests/unit/test_kwargs/test_multipart_data.py
--- a/tests/kwargs/test_multipart_data.py
+++ b/tests/unit/test_kwargs/test_multipart_data.py
@@ -15,7 +15,7 @@
 from litestar.status_codes import HTTP_201_CREATED, HTTP_400_BAD_REQUEST
 from litestar.testing import create_test_client
 from tests import Person, PersonFactory
-from tests.kwargs import Form
+from . import Form
 
 
 class FormData(BaseModel):
diff --git a/tests/kwargs/test_path_params.py b/tests/unit/test_kwargs/test_path_params.py
similarity index 100%
rename from tests/kwargs/test_path_params.py
rename to tests/unit/test_kwargs/test_path_params.py
diff --git a/tests/kwargs/test_query_params.py b/tests/unit/test_kwargs/test_query_params.py
similarity index 100%
rename from tests/kwargs/test_query_params.py
rename to tests/unit/test_kwargs/test_query_params.py
diff --git a/tests/kwargs/test_reserved_kwargs_injection.py b/tests/unit/test_kwargs/test_reserved_kwargs_injection.py
similarity index 100%
rename from tests/kwargs/test_reserved_kwargs_injection.py
rename to tests/unit/test_kwargs/test_reserved_kwargs_injection.py
diff --git a/tests/kwargs/test_url_encoded_data.py b/tests/unit/test_kwargs/test_url_encoded_data.py
similarity index 97%
rename from tests/kwargs/test_url_encoded_data.py
rename to tests/unit/test_kwargs/test_url_encoded_data.py
--- a/tests/kwargs/test_url_encoded_data.py
+++ b/tests/unit/test_kwargs/test_url_encoded_data.py
@@ -5,7 +5,8 @@
 from litestar.params import Body
 from litestar.status_codes import HTTP_201_CREATED
 from litestar.testing import create_test_client
-from tests.kwargs import Form
+
+from . import Form
 
 
 def test_request_body_url_encoded() -> None:
diff --git a/tests/kwargs/test_validations.py b/tests/unit/test_kwargs/test_validations.py
similarity index 100%
rename from tests/kwargs/test_validations.py
rename to tests/unit/test_kwargs/test_validations.py
diff --git a/tests/dependency_injection/__init__.py b/tests/unit/test_logging/__init__.py
similarity index 100%
rename from tests/dependency_injection/__init__.py
rename to tests/unit/test_logging/__init__.py
diff --git a/tests/logging_config/test_logging_config.py b/tests/unit/test_logging/test_logging_config.py
similarity index 94%
rename from tests/logging_config/test_logging_config.py
rename to tests/unit/test_logging/test_logging_config.py
--- a/tests/logging_config/test_logging_config.py
+++ b/tests/unit/test_logging/test_logging_config.py
@@ -5,18 +5,9 @@
 import pytest
 
 from litestar import Request, get
-from litestar.logging.config import (
-    LoggingConfig,
-    _get_default_handlers,
-    default_handlers,
-    default_picologging_handlers,
-)
-from litestar.logging.picologging import (
-    QueueListenerHandler as PicologgingQueueListenerHandler,
-)
-from litestar.logging.standard import (
-    QueueListenerHandler as StandardQueueListenerHandler,
-)
+from litestar.logging.config import LoggingConfig, _get_default_handlers, default_handlers, default_picologging_handlers
+from litestar.logging.picologging import QueueListenerHandler as PicologgingQueueListenerHandler
+from litestar.logging.standard import QueueListenerHandler as StandardQueueListenerHandler
 from litestar.status_codes import HTTP_200_OK
 from litestar.testing import create_test_client
 
diff --git a/tests/logging_config/test_structlog_config.py b/tests/unit/test_logging/test_structlog_config.py
similarity index 100%
rename from tests/logging_config/test_structlog_config.py
rename to tests/unit/test_logging/test_structlog_config.py
diff --git a/tests/dto/factory/backends/__init__.py b/tests/unit/test_middleware/__init__.py
similarity index 100%
rename from tests/dto/factory/backends/__init__.py
rename to tests/unit/test_middleware/__init__.py
diff --git a/tests/middleware/test_allowed_hosts_middleware.py b/tests/unit/test_middleware/test_allowed_hosts_middleware.py
similarity index 100%
rename from tests/middleware/test_allowed_hosts_middleware.py
rename to tests/unit/test_middleware/test_allowed_hosts_middleware.py
diff --git a/tests/middleware/test_base_authentication_middleware.py b/tests/unit/test_middleware/test_base_authentication_middleware.py
similarity index 100%
rename from tests/middleware/test_base_authentication_middleware.py
rename to tests/unit/test_middleware/test_base_authentication_middleware.py
diff --git a/tests/middleware/test_base_middleware.py b/tests/unit/test_middleware/test_base_middleware.py
similarity index 100%
rename from tests/middleware/test_base_middleware.py
rename to tests/unit/test_middleware/test_base_middleware.py
diff --git a/tests/middleware/test_compression_middleware.py b/tests/unit/test_middleware/test_compression_middleware.py
similarity index 100%
rename from tests/middleware/test_compression_middleware.py
rename to tests/unit/test_middleware/test_compression_middleware.py
diff --git a/tests/middleware/test_cors_middleware.py b/tests/unit/test_middleware/test_cors_middleware.py
similarity index 100%
rename from tests/middleware/test_cors_middleware.py
rename to tests/unit/test_middleware/test_cors_middleware.py
diff --git a/tests/middleware/test_csrf_middleware.py b/tests/unit/test_middleware/test_csrf_middleware.py
similarity index 98%
rename from tests/middleware/test_csrf_middleware.py
rename to tests/unit/test_middleware/test_csrf_middleware.py
--- a/tests/middleware/test_csrf_middleware.py
+++ b/tests/unit/test_middleware/test_csrf_middleware.py
@@ -175,7 +175,7 @@ def test_custom_csrf_config(get_handler: HTTPRouteHandler, post_handler: HTTPRou
         (MakoTemplateEngine, "${csrf_input}"),
     ),
 )
-def test_csrf_form_parsing(engine: Any, template: str, template_dir: Path) -> None:
+def test_csrf_form_parsing(engine: Any, template: str, tmp_path: Path) -> None:
     @get(path="/", media_type=MediaType.HTML)
     def handler() -> Template:
         return Template(template_name="abc.html")
@@ -187,13 +187,13 @@ def form_handler(data: dict = Body(media_type=RequestEncodingType.URL_ENCODED))
     with create_test_client(
         route_handlers=[handler, form_handler],
         template_config=TemplateConfig(
-            directory=template_dir,
+            directory=tmp_path,
             engine=engine,
         ),
         csrf_config=CSRFConfig(secret=str(urandom(10))),
     ) as client:
         url = str(client.base_url) + "/"
-        Path(template_dir / "abc.html").write_text(
+        Path(tmp_path / "abc.html").write_text(
             f'<html><body><div><form action="{url}" method="post">{template}</form></div></body></html>'
         )
         _ = client.get("/")
diff --git a/tests/middleware/test_exception_handler_middleware.py b/tests/unit/test_middleware/test_exception_handler_middleware.py
similarity index 100%
rename from tests/middleware/test_exception_handler_middleware.py
rename to tests/unit/test_middleware/test_exception_handler_middleware.py
diff --git a/tests/middleware/test_logging_middleware.py b/tests/unit/test_middleware/test_logging_middleware.py
similarity index 100%
rename from tests/middleware/test_logging_middleware.py
rename to tests/unit/test_middleware/test_logging_middleware.py
diff --git a/tests/middleware/test_middleware_handling.py b/tests/unit/test_middleware/test_middleware_handling.py
similarity index 100%
rename from tests/middleware/test_middleware_handling.py
rename to tests/unit/test_middleware/test_middleware_handling.py
diff --git a/tests/middleware/test_rate_limit_middleware.py b/tests/unit/test_middleware/test_rate_limit_middleware.py
similarity index 100%
rename from tests/middleware/test_rate_limit_middleware.py
rename to tests/unit/test_middleware/test_rate_limit_middleware.py
diff --git a/tests/events/__init__.py b/tests/unit/test_middleware/test_session/__init__.py
similarity index 100%
rename from tests/events/__init__.py
rename to tests/unit/test_middleware/test_session/__init__.py
diff --git a/tests/middleware/session/conftest.py b/tests/unit/test_middleware/test_session/conftest.py
similarity index 100%
rename from tests/middleware/session/conftest.py
rename to tests/unit/test_middleware/test_session/conftest.py
diff --git a/tests/middleware/session/test_client_side_backend.py b/tests/unit/test_middleware/test_session/test_client_side_backend.py
similarity index 100%
rename from tests/middleware/session/test_client_side_backend.py
rename to tests/unit/test_middleware/test_session/test_client_side_backend.py
diff --git a/tests/middleware/session/test_middleware.py b/tests/unit/test_middleware/test_session/test_middleware.py
similarity index 100%
rename from tests/middleware/session/test_middleware.py
rename to tests/unit/test_middleware/test_session/test_middleware.py
diff --git a/tests/middleware/session/test_server_side_backend.py b/tests/unit/test_middleware/test_session/test_server_side_backend.py
similarity index 100%
rename from tests/middleware/session/test_server_side_backend.py
rename to tests/unit/test_middleware/test_session/test_server_side_backend.py
diff --git a/tests/handlers/__init__.py b/tests/unit/test_openapi/__init__.py
similarity index 100%
rename from tests/handlers/__init__.py
rename to tests/unit/test_openapi/__init__.py
diff --git a/tests/openapi/conftest.py b/tests/unit/test_openapi/conftest.py
similarity index 98%
rename from tests/openapi/conftest.py
rename to tests/unit/test_openapi/conftest.py
--- a/tests/openapi/conftest.py
+++ b/tests/unit/test_openapi/conftest.py
@@ -12,7 +12,8 @@
 from litestar.params import Parameter
 from litestar.partial import Partial
 from tests import Person, PersonFactory, Pet, VanillaDataClassPerson
-from tests.openapi.utils import Gender, PetException
+
+from .utils import Gender, PetException
 
 
 def create_person_controller() -> Type[Controller]:
diff --git a/tests/openapi/test_config.py b/tests/unit/test_openapi/test_config.py
similarity index 100%
rename from tests/openapi/test_config.py
rename to tests/unit/test_openapi/test_config.py
diff --git a/tests/openapi/test_constrained_fields.py b/tests/unit/test_openapi/test_constrained_fields.py
similarity index 99%
rename from tests/openapi/test_constrained_fields.py
rename to tests/unit/test_openapi/test_constrained_fields.py
--- a/tests/openapi/test_constrained_fields.py
+++ b/tests/unit/test_openapi/test_constrained_fields.py
@@ -12,7 +12,8 @@
 from litestar._openapi.schema_generation.schema import create_schema
 from litestar._signature.field import SignatureField
 from litestar.openapi.spec.enums import OpenAPIFormat, OpenAPIType
-from tests.openapi.utils import (
+
+from .utils import (
     constrained_collection,
     constrained_dates,
     constrained_numbers,
diff --git a/tests/openapi/test_controller.py b/tests/unit/test_openapi/test_controller.py
similarity index 100%
rename from tests/openapi/test_controller.py
rename to tests/unit/test_openapi/test_controller.py
diff --git a/tests/openapi/test_integration.py b/tests/unit/test_openapi/test_integration.py
similarity index 100%
rename from tests/openapi/test_integration.py
rename to tests/unit/test_openapi/test_integration.py
diff --git a/tests/openapi/test_parameters.py b/tests/unit/test_openapi/test_parameters.py
similarity index 100%
rename from tests/openapi/test_parameters.py
rename to tests/unit/test_openapi/test_parameters.py
diff --git a/tests/openapi/test_path_item.py b/tests/unit/test_openapi/test_path_item.py
similarity index 100%
rename from tests/openapi/test_path_item.py
rename to tests/unit/test_openapi/test_path_item.py
diff --git a/tests/openapi/test_request_body.py b/tests/unit/test_openapi/test_request_body.py
similarity index 100%
rename from tests/openapi/test_request_body.py
rename to tests/unit/test_openapi/test_request_body.py
diff --git a/tests/openapi/test_responses.py b/tests/unit/test_openapi/test_responses.py
similarity index 99%
rename from tests/openapi/test_responses.py
rename to tests/unit/test_openapi/test_responses.py
--- a/tests/openapi/test_responses.py
+++ b/tests/unit/test_openapi/test_responses.py
@@ -36,7 +36,8 @@
     HTTP_406_NOT_ACCEPTABLE,
 )
 from tests import Person, PersonFactory
-from tests.openapi.utils import PetException
+
+from .utils import PetException
 
 
 def get_registered_route_handler(handler: "HTTPRouteHandler | type[Controller]", name: str) -> HTTPRouteHandler:
@@ -62,7 +63,7 @@ def test_create_responses(person_controller: Type[Controller], pet_controller: T
 
     handler = get_registered_route_handler(
         pet_controller,
-        "tests.openapi.conftest.create_pet_controller.<locals>.PetController.get_pets_or_owners",
+        "tests.unit.test_openapi.conftest.create_pet_controller.<locals>.PetController.get_pets_or_owners",
     )
     responses = create_responses(
         route_handler=handler,
diff --git a/tests/openapi/test_schema.py b/tests/unit/test_openapi/test_schema.py
similarity index 100%
rename from tests/openapi/test_schema.py
rename to tests/unit/test_openapi/test_schema.py
diff --git a/tests/openapi/test_security_schemes.py b/tests/unit/test_openapi/test_security_schemes.py
similarity index 100%
rename from tests/openapi/test_security_schemes.py
rename to tests/unit/test_openapi/test_security_schemes.py
diff --git a/tests/openapi/test_spec_generation.py b/tests/unit/test_openapi/test_spec_generation.py
similarity index 100%
rename from tests/openapi/test_spec_generation.py
rename to tests/unit/test_openapi/test_spec_generation.py
diff --git a/tests/openapi/test_tags.py b/tests/unit/test_openapi/test_tags.py
similarity index 100%
rename from tests/openapi/test_tags.py
rename to tests/unit/test_openapi/test_tags.py
diff --git a/tests/handlers/asgi/__init__.py b/tests/unit/test_openapi/test_typescript_converter/__init__.py
similarity index 100%
rename from tests/handlers/asgi/__init__.py
rename to tests/unit/test_openapi/test_typescript_converter/__init__.py
diff --git a/tests/openapi/typescript_converter/test_converter.py b/tests/unit/test_openapi/test_typescript_converter/test_converter.py
similarity index 100%
rename from tests/openapi/typescript_converter/test_converter.py
rename to tests/unit/test_openapi/test_typescript_converter/test_converter.py
diff --git a/tests/openapi/typescript_converter/test_schema_parsing.py b/tests/unit/test_openapi/test_typescript_converter/test_schema_parsing.py
similarity index 100%
rename from tests/openapi/typescript_converter/test_schema_parsing.py
rename to tests/unit/test_openapi/test_typescript_converter/test_schema_parsing.py
diff --git a/tests/openapi/typescript_converter/test_typescript_types.py b/tests/unit/test_openapi/test_typescript_converter/test_typescript_types.py
similarity index 100%
rename from tests/openapi/typescript_converter/test_typescript_types.py
rename to tests/unit/test_openapi/test_typescript_converter/test_typescript_types.py
diff --git a/tests/openapi/utils.py b/tests/unit/test_openapi/utils.py
similarity index 100%
rename from tests/openapi/utils.py
rename to tests/unit/test_openapi/utils.py
diff --git a/tests/test_pagination.py b/tests/unit/test_pagination.py
similarity index 100%
rename from tests/test_pagination.py
rename to tests/unit/test_pagination.py
diff --git a/tests/dependency_injection/test_dependency.py b/tests/unit/test_params.py
similarity index 53%
rename from tests/dependency_injection/test_dependency.py
rename to tests/unit/test_params.py
--- a/tests/dependency_injection/test_dependency.py
+++ b/tests/unit/test_params.py
@@ -1,15 +1,94 @@
-from typing import Any, AsyncGenerator, Dict, Generator, List, Optional
+from typing import Any, Dict, List, Optional
 
 import pytest
+from typing_extensions import Annotated
 
-from litestar import Controller, Litestar, get
+from litestar import Controller, Litestar, get, post
 from litestar.di import Provide
 from litestar.exceptions import ImproperlyConfiguredException
-from litestar.params import Dependency
-from litestar.status_codes import HTTP_200_OK, HTTP_500_INTERNAL_SERVER_ERROR
+from litestar.params import Body, Dependency, Parameter
+from litestar.status_codes import HTTP_200_OK, HTTP_201_CREATED, HTTP_400_BAD_REQUEST, HTTP_500_INTERNAL_SERVER_ERROR
 from litestar.testing import create_test_client
 
 
+@pytest.mark.parametrize("backend", ("pydantic", "attrs"))
+def test_parsing_of_parameter_as_annotated(backend: Any) -> None:
+    @get(path="/")
+    def handler(param: Annotated[str, Parameter(min_length=1)]) -> str:
+        return param
+
+    with create_test_client(handler, _preferred_validation_backend=backend) as client:
+        response = client.get("/")
+        assert response.status_code == HTTP_400_BAD_REQUEST
+
+        response = client.get("/?param=a")
+        assert response.status_code == HTTP_200_OK
+
+
+@pytest.mark.parametrize("backend", ("pydantic", "attrs"))
+def test_parsing_of_parameter_as_default_value(backend: Any) -> None:
+    @get(path="/")
+    def handler(param: str = Parameter(min_length=1)) -> str:
+        return param
+
+    with create_test_client(handler, _preferred_validation_backend=backend) as client:
+        response = client.get("/?param=")
+        assert response.status_code == HTTP_400_BAD_REQUEST
+
+        response = client.get("/?param=a")
+        assert response.status_code == HTTP_200_OK
+
+
+@pytest.mark.parametrize("backend", ("pydantic", "attrs"))
+def test_parsing_of_body_as_annotated(backend: Any) -> None:
+    @post(path="/")
+    def handler(data: Annotated[List[str], Body(min_items=1)]) -> List[str]:
+        return data
+
+    with create_test_client(handler, _preferred_validation_backend=backend) as client:
+        response = client.post("/", json=[])
+        assert response.status_code == HTTP_400_BAD_REQUEST
+
+        response = client.post("/", json=["a"])
+        assert response.status_code == HTTP_201_CREATED
+
+
+@pytest.mark.parametrize("backend", ("pydantic", "attrs"))
+def test_parsing_of_body_as_default_value(backend: Any) -> None:
+    @post(path="/")
+    def handler(data: List[str] = Body(min_items=1)) -> List[str]:
+        return data
+
+    with create_test_client(handler, _preferred_validation_backend=backend) as client:
+        response = client.post("/", json=[])
+        assert response.status_code == HTTP_400_BAD_REQUEST
+
+        response = client.post("/", json=["a"])
+        assert response.status_code == HTTP_201_CREATED
+
+
+@pytest.mark.parametrize("backend", ("pydantic", "attrs"))
+def test_parsing_of_dependency_as_annotated(backend: Any) -> None:
+    @get(path="/", dependencies={"dep": Provide(lambda: None, sync_to_thread=False)})
+    def handler(dep: Annotated[int, Dependency(skip_validation=True)]) -> int:
+        return dep
+
+    with create_test_client(handler, _preferred_validation_backend=backend) as client:
+        response = client.get("/")
+        assert response.text == "null"
+
+
+@pytest.mark.parametrize("backend", ("pydantic", "attrs"))
+def test_parsing_of_dependency_as_default_value(backend: Any) -> None:
+    @get(path="/", dependencies={"dep": Provide(lambda: None, sync_to_thread=False)})
+    def handler(dep: int = Dependency(skip_validation=True)) -> int:
+        return dep
+
+    with create_test_client(handler, _preferred_validation_backend=backend) as client:
+        response = client.get("/")
+        assert response.text == "null"
+
+
 @pytest.mark.parametrize(
     "dependency, expected",
     [
@@ -28,7 +107,7 @@ def handler(value: Optional[int] = dependency) -> Dict[str, Optional[int]]:
         assert resp.json() == {"value": expected}
 
 
-def test_non_optional_with_default() -> None:
+def test_dependency_non_optional_with_default() -> None:
     @get("/")
     def handler(value: int = Dependency(default=13)) -> Dict[str, int]:
         return {"value": value}
@@ -38,7 +117,7 @@ def handler(value: int = Dependency(default=13)) -> Dict[str, int]:
         assert resp.json() == {"value": 13}
 
 
-def test_no_default_dependency_provided() -> None:
+def test_dependency_no_default() -> None:
     @get(dependencies={"value": Provide(lambda: 13, sync_to_thread=False)})
     def test(value: int = Dependency()) -> Dict[str, int]:
         return {"value": value}
@@ -105,7 +184,7 @@ def skipped(value: int = Dependency(default=1, skip_validation=True)) -> Dict[st
         assert skipped_resp.json() == {"value": 1}
 
 
-def test_nested_sequence_dependency() -> None:
+def test_dependency_nested_sequence() -> None:
     class Obj:
         def __init__(self, seq: List[str]) -> None:
             self.seq = seq
@@ -130,27 +209,3 @@ def get_seq(seq: List[str]) -> List[str]:
         assert resp.json() == ["a", "b", "c"]
         resp = client.get("/obj", params={"seq": seq})
         assert resp.json() == ["a", "b", "c"]
-
-
-def sync_callable() -> float:
-    return 0.1
-
-
-async def async_callable() -> float:
-    return 0.1
-
-
-def sync_generator() -> Generator[float, None, None]:
-    yield 0.1
-
-
-async def async_generator() -> AsyncGenerator[float, None]:
-    yield 0.1
-
-
-@pytest.mark.parametrize(
-    ("dep", "exp"),
-    [(sync_callable, True), (async_callable, False), (sync_generator, True), (async_generator, True)],
-)
-def test_dependency_has_async_callable(dep: Any, exp: bool) -> None:
-    assert Provide(dep).has_sync_callable is exp
diff --git a/tests/test_parsers.py b/tests/unit/test_parsers.py
similarity index 100%
rename from tests/test_parsers.py
rename to tests/unit/test_parsers.py
diff --git a/tests/test_partial.py b/tests/unit/test_partial.py
similarity index 100%
rename from tests/test_partial.py
rename to tests/unit/test_partial.py
diff --git a/tests/test_plugins.py b/tests/unit/test_plugins.py
similarity index 100%
rename from tests/test_plugins.py
rename to tests/unit/test_plugins.py
diff --git a/tests/handlers/base/__init__.py b/tests/unit/test_response/__init__.py
similarity index 100%
rename from tests/handlers/base/__init__.py
rename to tests/unit/test_response/__init__.py
diff --git a/tests/response/test_base_response.py b/tests/unit/test_response/test_base_response.py
similarity index 100%
rename from tests/response/test_base_response.py
rename to tests/unit/test_response/test_base_response.py
--- a/tests/response/test_base_response.py
+++ b/tests/unit/test_response/test_base_response.py
@@ -171,11 +171,6 @@ def handler() -> Any:
             assert response.status_code == HTTP_200_OK
 
 
-def test_head_response_doesnt_support_content() -> None:
-    with pytest.raises(ImproperlyConfiguredException):
-        ASGIResponse(body=b"hello world", media_type=MediaType.TEXT, is_head_response=True)
-
-
 def test_get_serializer() -> None:
     class Foo:
         pass
@@ -195,3 +190,8 @@ class FooResponse(Response):
     assert (
         get_serializer(FooResponse(None, type_encoders={Foo: lambda f: "foo"}).response_type_encoders)(Foo()) == "foo"
     )
+
+
+def test_head_response_doesnt_support_content() -> None:
+    with pytest.raises(ImproperlyConfiguredException):
+        ASGIResponse(body=b"hello world", media_type=MediaType.TEXT, is_head_response=True)
diff --git a/tests/response/test_file_response.py b/tests/unit/test_response/test_file_response.py
similarity index 53%
rename from tests/response/test_file_response.py
rename to tests/unit/test_response/test_file_response.py
--- a/tests/response/test_file_response.py
+++ b/tests/unit/test_response/test_file_response.py
@@ -1,17 +1,21 @@
+import os
 from email.utils import formatdate
-from os import urandom
+from os import stat, urandom
 from pathlib import Path
 from typing import Any
 
 import pytest
+from fsspec.implementations.local import LocalFileSystem
 
 from litestar import get
 from litestar.connection.base import empty_send
+from litestar.datastructures import ETag
 from litestar.exceptions import ImproperlyConfiguredException
 from litestar.file_system import BaseLocalFileSystem, FileSystemAdapter
 from litestar.response.file import ASGIFileResponse, File, async_file_iterator
 from litestar.status_codes import HTTP_200_OK
 from litestar.testing import create_test_client
+from litestar.types import FileSystemProtocol
 
 
 @pytest.mark.parametrize("content_disposition_type", ("inline", "attachment"))
@@ -97,13 +101,6 @@ async def test_file_response_with_directory_raises_error(tmpdir: Path) -> None:
         await asgi_response.start_response(empty_send)
 
 
-async def test_file_response_with_missing_file_raises_error(tmpdir: Path) -> None:
-    path = tmpdir / "404.txt"
-    with pytest.raises(ImproperlyConfiguredException):
-        asgi_response = ASGIFileResponse(file_path=path, filename="404.txt")
-        await asgi_response.start_response(empty_send)
-
-
 @pytest.mark.parametrize("chunk_size", [4, 8, 16, 256, 512, 1024, 2048])
 async def test_file_iterator(tmpdir: Path, chunk_size: int) -> None:
     content = urandom(1024)
@@ -135,3 +132,147 @@ def handler() -> File:
         assert response.status_code == HTTP_200_OK
         assert response.content == content
         assert response.headers["content-length"] == str(len(content))
+
+
+@pytest.mark.parametrize("file_system", (BaseLocalFileSystem(), LocalFileSystem()))
+def test_file_with_different_file_systems(tmpdir: "Path", file_system: "FileSystemProtocol") -> None:
+    path = tmpdir / "text.txt"
+    path.write_text("content", "utf-8")
+
+    @get("/", media_type="application/octet-stream")
+    def handler() -> File:
+        return File(
+            filename="text.txt",
+            path=path,
+            file_system=file_system,
+        )
+
+    with create_test_client(handler, debug=True) as client:
+        response = client.get("/")
+        assert response.status_code == HTTP_200_OK
+        assert response.text == "content"
+        assert response.headers.get("content-disposition") == 'attachment; filename="text.txt"'
+
+
+def test_file_with_passed_in_file_info(tmpdir: "Path") -> None:
+    path = tmpdir / "text.txt"
+    path.write_text("content", "utf-8")
+
+    fs = LocalFileSystem()
+    fs_info = fs.info(tmpdir / "text.txt")
+
+    assert fs_info
+
+    @get("/", media_type="application/octet-stream")
+    def handler() -> File:
+        return File(filename="text.txt", path=path, file_system=fs, file_info=fs_info)  # pyright: ignore
+
+    with create_test_client(handler) as client:
+        response = client.get("/")
+        assert response.status_code == HTTP_200_OK, response.text
+        assert response.text == "content"
+        assert response.headers.get("content-disposition") == 'attachment; filename="text.txt"'
+
+
+def test_file_with_passed_in_stat_result(tmpdir: "Path") -> None:
+    path = tmpdir / "text.txt"
+    path.write_text("content", "utf-8")
+
+    fs = LocalFileSystem()
+    stat_result = stat(path)
+
+    @get("/", media_type="application/octet-stream")
+    def handler() -> File:
+        return File(filename="text.txt", path=path, file_system=fs, stat_result=stat_result)
+
+    with create_test_client(handler) as client:
+        response = client.get("/")
+        assert response.status_code == HTTP_200_OK
+        assert response.text == "content"
+        assert response.headers.get("content-disposition") == 'attachment; filename="text.txt"'
+
+
+async def test_file_with_symbolic_link(tmpdir: "Path") -> None:
+    path = tmpdir / "text.txt"
+    path.write_text("content", "utf-8")
+
+    linked = tmpdir / "alt.txt"
+    os.symlink(path, linked, target_is_directory=False)
+
+    fs = BaseLocalFileSystem()
+    file_info = await fs.info(linked)
+
+    assert file_info["islink"]
+
+    @get("/", media_type="application/octet-stream")
+    def handler() -> File:
+        return File(filename="alt.txt", path=linked, file_system=fs, file_info=file_info)
+
+    with create_test_client(handler) as client:
+        response = client.get("/")
+        assert response.status_code == HTTP_200_OK
+        assert response.text == "content"
+        assert response.headers.get("content-disposition") == 'attachment; filename="alt.txt"'
+
+
+async def test_file_sets_etag_correctly(tmpdir: "Path") -> None:
+    path = tmpdir / "file.txt"
+    content = b"<file content>"
+    Path(path).write_bytes(content)
+    etag = ETag(value="special")
+
+    @get("/")
+    def handler() -> File:
+        return File(path=path, etag=etag)
+
+    with create_test_client(handler) as client:
+        response = client.get("/")
+        assert response.status_code == HTTP_200_OK
+        assert response.headers["etag"] == '"special"'
+
+
+def test_file_system_validation(tmpdir: "Path") -> None:
+    path = tmpdir / "text.txt"
+    path.write_text("content", "utf-8")
+
+    class FSWithoutOpen:
+        def info(self) -> None:
+            return
+
+    with pytest.raises(ImproperlyConfiguredException):
+        File(
+            filename="text.txt",
+            path=path,
+            file_system=FSWithoutOpen(),  # type:ignore[arg-type]
+        )
+
+    class FSWithoutInfo:
+        def open(self) -> None:
+            return
+
+    with pytest.raises(ImproperlyConfiguredException):
+        File(
+            filename="text.txt",
+            path=path,
+            file_system=FSWithoutInfo(),  # type:ignore[arg-type]
+        )
+
+    class ImplementedFS:
+        def info(self) -> None:
+            return
+
+        def open(self) -> None:
+            return
+
+    assert File(
+        filename="text.txt",
+        path=path,
+        file_system=ImplementedFS(),  # type:ignore[arg-type]
+    )
+
+
+async def test_file_response_with_missing_file_raises_error(tmpdir: Path) -> None:
+    path = tmpdir / "404.txt"
+    with pytest.raises(ImproperlyConfiguredException):
+        asgi_response = ASGIFileResponse(file_path=path, filename="404.txt")
+        await asgi_response.start_response(empty_send)
diff --git a/tests/response/test_redirect_response.py b/tests/unit/test_response/test_redirect_response.py
similarity index 71%
rename from tests/response/test_redirect_response.py
rename to tests/unit/test_response/test_redirect_response.py
--- a/tests/response/test_redirect_response.py
+++ b/tests/unit/test_response/test_redirect_response.py
@@ -3,15 +3,16 @@
 https://github.com/encode/starlette/blob/master/tests/test_responses.py And are meant to ensure our compatibility with
 their API.
 """
-from typing import TYPE_CHECKING
+from typing import TYPE_CHECKING, Optional
 
 import pytest
 
+from litestar import get
 from litestar.exceptions import ImproperlyConfiguredException
 from litestar.response.base import ASGIResponse
-from litestar.response.redirect import ASGIRedirectResponse
+from litestar.response.redirect import ASGIRedirectResponse, Redirect
 from litestar.status_codes import HTTP_200_OK
-from litestar.testing import TestClient
+from litestar.testing import TestClient, create_test_client
 
 if TYPE_CHECKING:
     from litestar.types import Receive, Scope, Send
@@ -81,3 +82,34 @@ async def app(scope: "Scope", receive: "Receive", send: "Send") -> None:
 def test_redirect_response_media_type_validation() -> None:
     with pytest.raises(ImproperlyConfiguredException):
         ASGIRedirectResponse(path="/", media_type="application/json")
+
+
+@pytest.mark.parametrize(
+    "status_code,expected_status_code",
+    [
+        (301, 301),
+        (302, 302),
+        (303, 303),
+        (307, 307),
+        (308, 308),
+    ],
+)
+def test_redirect_dynamic_status_code(status_code: Optional[int], expected_status_code: int) -> None:
+    @get("/")
+    def handler() -> Redirect:
+        return Redirect(path="/something-else", status_code=status_code)  # type: ignore[arg-type]
+
+    with create_test_client([handler], debug=True) as client:
+        res = client.get("/", follow_redirects=False)
+        assert res.status_code == expected_status_code
+
+
+@pytest.mark.parametrize("handler_status_code", [301, 307, None])
+def test_redirect(handler_status_code: Optional[int]) -> None:
+    @get("/", status_code=handler_status_code)
+    def handler() -> Redirect:
+        return Redirect(path="/something-else", status_code=301)
+
+    with create_test_client([handler]) as client:
+        res = client.get("/", follow_redirects=False)
+        assert res.status_code == 301
diff --git a/tests/response/test_response_class.py b/tests/unit/test_response/test_response_class.py
similarity index 100%
rename from tests/response/test_response_class.py
rename to tests/unit/test_response/test_response_class.py
diff --git a/tests/response/test_response_cookies.py b/tests/unit/test_response/test_response_cookies.py
similarity index 100%
rename from tests/response/test_response_cookies.py
rename to tests/unit/test_response/test_response_cookies.py
diff --git a/tests/response/test_response_headers.py b/tests/unit/test_response/test_response_headers.py
similarity index 96%
rename from tests/response/test_response_headers.py
rename to tests/unit/test_response/test_response_headers.py
--- a/tests/response/test_response_headers.py
+++ b/tests/unit/test_response/test_response_headers.py
@@ -5,7 +5,6 @@
 from litestar import Controller, HttpMethod, Litestar, Router, get, post
 from litestar.datastructures import CacheControlHeader, ETag, ResponseHeader
 from litestar.datastructures.headers import Header
-from litestar.exceptions import ImproperlyConfiguredException
 from litestar.status_codes import HTTP_201_CREATED
 from litestar.testing import TestClient, create_test_client
 
@@ -73,12 +72,6 @@ def handler_one() -> None:
     assert handler_one.resolve_response_headers() == frozenset([ResponseHeader(name="foo", value="bar")])
 
 
-def test_response_headers_validation() -> None:
-    ResponseHeader(name="test", documentation_only=True)
-    with pytest.raises(ImproperlyConfiguredException):
-        ResponseHeader(name="test")
-
-
 def test_response_headers_rendering() -> None:
     @post(
         path="/test",
diff --git a/tests/response/test_serialization.py b/tests/unit/test_response/test_serialization.py
similarity index 100%
rename from tests/response/test_serialization.py
rename to tests/unit/test_response/test_serialization.py
diff --git a/tests/response/test_streaming_response.py b/tests/unit/test_response/test_streaming_response.py
similarity index 100%
rename from tests/response/test_streaming_response.py
rename to tests/unit/test_response/test_streaming_response.py
diff --git a/tests/response/test_type_encoders.py b/tests/unit/test_response/test_type_encoders.py
similarity index 100%
rename from tests/response/test_type_encoders.py
rename to tests/unit/test_response/test_type_encoders.py
diff --git a/tests/handlers/http/__init__.py b/tests/unit/test_security/__init__.py
similarity index 100%
rename from tests/handlers/http/__init__.py
rename to tests/unit/test_security/__init__.py
diff --git a/tests/security/test_security.py b/tests/unit/test_security/test_security.py
similarity index 100%
rename from tests/security/test_security.py
rename to tests/unit/test_security/test_security.py
diff --git a/tests/security/test_session_auth.py b/tests/unit/test_security/test_session_auth.py
similarity index 100%
rename from tests/security/test_session_auth.py
rename to tests/unit/test_security/test_session_auth.py
diff --git a/tests/test_serialization.py b/tests/unit/test_serialization.py
similarity index 100%
rename from tests/test_serialization.py
rename to tests/unit/test_serialization.py
diff --git a/tests/handlers/websocket/__init__.py b/tests/unit/test_signature/__init__.py
similarity index 100%
rename from tests/handlers/websocket/__init__.py
rename to tests/unit/test_signature/__init__.py
diff --git a/tests/signature/test_attrs_signature_modelling.py b/tests/unit/test_signature/test_attrs_signature_modelling.py
similarity index 100%
rename from tests/signature/test_attrs_signature_modelling.py
rename to tests/unit/test_signature/test_attrs_signature_modelling.py
diff --git a/tests/signature/test_parsing.py b/tests/unit/test_signature/test_parsing.py
similarity index 100%
rename from tests/signature/test_parsing.py
rename to tests/unit/test_signature/test_parsing.py
diff --git a/tests/signature/test_signature_validation.py b/tests/unit/test_signature/test_signature_validation.py
similarity index 100%
rename from tests/signature/test_signature_validation.py
rename to tests/unit/test_signature/test_signature_validation.py
diff --git a/tests/signature/test_utils.py b/tests/unit/test_signature/test_utils.py
similarity index 100%
rename from tests/signature/test_utils.py
rename to tests/unit/test_signature/test_utils.py
diff --git a/tests/life_cycle_hooks/__init__.py b/tests/unit/test_static_files/__init__.py
similarity index 100%
rename from tests/life_cycle_hooks/__init__.py
rename to tests/unit/test_static_files/__init__.py
diff --git a/tests/static_files/test_file_serving_resolution.py b/tests/unit/test_static_files/test_file_serving_resolution.py
similarity index 100%
rename from tests/static_files/test_file_serving_resolution.py
rename to tests/unit/test_static_files/test_file_serving_resolution.py
diff --git a/tests/static_files/test_html_mode.py b/tests/unit/test_static_files/test_html_mode.py
similarity index 100%
rename from tests/static_files/test_html_mode.py
rename to tests/unit/test_static_files/test_html_mode.py
diff --git a/tests/static_files/test_static_files_validation.py b/tests/unit/test_static_files/test_static_files_validation.py
similarity index 100%
rename from tests/static_files/test_static_files_validation.py
rename to tests/unit/test_static_files/test_static_files_validation.py
diff --git a/tests/test_stores.py b/tests/unit/test_stores.py
similarity index 100%
rename from tests/test_stores.py
rename to tests/unit/test_stores.py
diff --git a/tests/logging_config/__init__.py b/tests/unit/test_template/__init__.py
similarity index 100%
rename from tests/logging_config/__init__.py
rename to tests/unit/test_template/__init__.py
diff --git a/tests/template/test_built_in.py b/tests/unit/test_template/test_built_in.py
similarity index 84%
rename from tests/template/test_built_in.py
rename to tests/unit/test_template/test_built_in.py
--- a/tests/template/test_built_in.py
+++ b/tests/unit/test_template/test_built_in.py
@@ -41,8 +41,8 @@ def engine_test(request: Any) -> EngineTest:
 
 
 @pytest.fixture()
-def index_handler(engine_test: EngineTest, template_dir: Path) -> "HTTPRouteHandler":
-    Path(template_dir / "index.html").write_text(engine_test.index_template)
+def index_handler(engine_test: EngineTest, tmp_path: Path) -> "HTTPRouteHandler":
+    Path(tmp_path / "index.html").write_text(engine_test.index_template)
 
     @get(path="/")
     def index_handler() -> Template:
@@ -52,8 +52,8 @@ def index_handler() -> Template:
 
 
 @pytest.fixture()
-def nested_path_handler(engine_test: EngineTest, template_dir: Path) -> "HTTPRouteHandler":
-    nested_path = template_dir / "nested-dir"
+def nested_path_handler(engine_test: EngineTest, tmp_path: Path) -> "HTTPRouteHandler":
+    nested_path = tmp_path / "nested-dir"
     nested_path.mkdir()
     Path(nested_path / "nested.html").write_text(engine_test.nested_template)
 
@@ -65,8 +65,8 @@ def nested_path_handler() -> Template:
 
 
 @pytest.fixture()
-def template_config(engine_test: EngineTest, template_dir: Path) -> TemplateConfig:
-    return TemplateConfig(engine=engine_test.engine, directory=template_dir)
+def template_config(engine_test: EngineTest, tmp_path: Path) -> TemplateConfig:
+    return TemplateConfig(engine=engine_test.engine, directory=tmp_path)
 
 
 def test_template(index_handler: "HTTPRouteHandler", template_config: TemplateConfig) -> None:
@@ -77,7 +77,7 @@ def test_template(index_handler: "HTTPRouteHandler", template_config: TemplateCo
         assert response.headers["Content-Type"] == "text/html; charset=utf-8"
 
 
-def test_nested_template_directory(nested_path_handler: "HTTPRouteHandler", template_config: TemplateConfig) -> None:
+def test_nested_tmp_pathectory(nested_path_handler: "HTTPRouteHandler", template_config: TemplateConfig) -> None:
     with create_test_client(route_handlers=[nested_path_handler], template_config=template_config) as client:
         response = client.request("GET", "/nested")
         assert response.status_code == 200, response.text
@@ -96,8 +96,8 @@ def invalid_template_name_handler() -> Template:
         assert response.json() == {"detail": "Template invalid.html not found.", "status_code": 500}
 
 
-def test_no_context(template_dir: Path, template_config: TemplateConfig) -> None:
-    Path(template_dir / "index.html").write_text("<html>This works!</html>")
+def test_no_context(tmp_path: Path, template_config: TemplateConfig) -> None:
+    Path(tmp_path / "index.html").write_text("<html>This works!</html>")
 
     @get(path="/")
     def index() -> Template:
diff --git a/tests/template/test_builtin_functions.py b/tests/unit/test_template/test_builtin_functions.py
similarity index 80%
rename from tests/template/test_builtin_functions.py
rename to tests/unit/test_template/test_builtin_functions.py
--- a/tests/template/test_builtin_functions.py
+++ b/tests/unit/test_template/test_builtin_functions.py
@@ -15,8 +15,8 @@
 
 
 @pytest.mark.xfail(sys.platform == "win32", reason="For some reason this is flaky on windows")
-def test_jinja_url_for(template_dir: Path) -> None:
-    template_config = TemplateConfig(engine=JinjaTemplateEngine, directory=template_dir)
+def test_jinja_url_for(tmp_path: Path) -> None:
+    template_config = TemplateConfig(engine=JinjaTemplateEngine, directory=tmp_path)
 
     @get(path="/")
     def tpl_renderer() -> Template:
@@ -33,7 +33,7 @@ def complex_handler() -> None:
     with create_test_client(
         route_handlers=[simple_handler, complex_handler, tpl_renderer], template_config=template_config, debug=True
     ) as client:
-        Path(template_dir / "tpl.html").write_text("{{ url_for('simple') }}")
+        Path(tmp_path / "tpl.html").write_text("{{ url_for('simple') }}")
 
         response = client.get("/")
         assert response.status_code == 200
@@ -42,7 +42,7 @@ def complex_handler() -> None:
     with create_test_client(
         route_handlers=[simple_handler, complex_handler, tpl_renderer], template_config=template_config
     ) as client:
-        Path(template_dir / "tpl.html").write_text("{{ url_for('complex', int_param=100, time_param='18:00') }}")
+        Path(tmp_path / "tpl.html").write_text("{{ url_for('complex', int_param=100, time_param='18:00') }}")
 
         response = client.get("/")
         assert response.status_code == 200
@@ -52,7 +52,7 @@ def complex_handler() -> None:
         route_handlers=[simple_handler, complex_handler, tpl_renderer], template_config=template_config
     ) as client:
         # missing route params should cause 500 err
-        Path(template_dir / "tpl.html").write_text("{{ url_for('complex') }}")
+        Path(tmp_path / "tpl.html").write_text("{{ url_for('complex') }}")
         response = client.get("/")
         assert response.status_code == 500
 
@@ -60,7 +60,7 @@ def complex_handler() -> None:
         route_handlers=[simple_handler, complex_handler, tpl_renderer], template_config=template_config
     ) as client:
         # wrong param type should also cause 500 error
-        Path(template_dir / "tpl.html").write_text("{{ url_for('complex', int_param='100', time_param='18:00') }}")
+        Path(tmp_path / "tpl.html").write_text("{{ url_for('complex', int_param='100', time_param='18:00') }}")
 
         response = client.get("/")
         assert response.status_code == 500
@@ -68,15 +68,15 @@ def complex_handler() -> None:
     with create_test_client(
         route_handlers=[simple_handler, complex_handler, tpl_renderer], template_config=template_config
     ) as client:
-        Path(template_dir / "tpl.html").write_text("{{ url_for('non-existent-route') }}")
+        Path(tmp_path / "tpl.html").write_text("{{ url_for('non-existent-route') }}")
 
         response = client.get("/")
         assert response.status_code == 500
 
 
 @pytest.mark.xfail(sys.platform == "win32", reason="For some reason this is flaky on windows")
-def test_jinja_url_for_static_asset(template_dir: Path, tmp_path: Path) -> None:
-    template_config = TemplateConfig(engine=JinjaTemplateEngine, directory=template_dir)
+def test_jinja_url_for_static_asset(tmp_path: Path) -> None:
+    template_config = TemplateConfig(engine=JinjaTemplateEngine, directory=tmp_path)
 
     @get(path="/", name="tpl_renderer")
     def tpl_renderer() -> Template:
@@ -87,7 +87,7 @@ def tpl_renderer() -> Template:
         template_config=template_config,
         static_files_config=[StaticFilesConfig(path="/static/css", directories=[tmp_path], name="css")],
     ) as client:
-        Path(template_dir / "tpl.html").write_text("{{ url_for_static_asset('css', 'main/main.css') }}")
+        Path(tmp_path / "tpl.html").write_text("{{ url_for_static_asset('css', 'main/main.css') }}")
 
         response = client.get("/")
         assert response.status_code == 200
@@ -98,7 +98,7 @@ def tpl_renderer() -> Template:
         template_config=template_config,
         static_files_config=[StaticFilesConfig(path="/static/css", directories=[tmp_path], name="css")],
     ) as client:
-        Path(template_dir / "tpl.html").write_text("{{ url_for_static_asset('non-existent', 'main.css') }}")
+        Path(tmp_path / "tpl.html").write_text("{{ url_for_static_asset('non-existent', 'main.css') }}")
 
         response = client.get("/")
         assert response.status_code == 500
@@ -108,7 +108,7 @@ def tpl_renderer() -> Template:
         template_config=template_config,
         static_files_config=[StaticFilesConfig(path="/static/css", directories=[tmp_path], name="css")],
     ) as client:
-        Path(template_dir / "tpl.html").write_text("{{ url_for_static_asset('tpl_renderer', 'main.css') }}")
+        Path(tmp_path / "tpl.html").write_text("{{ url_for_static_asset('tpl_renderer', 'main.css') }}")
 
         response = client.get("/")
         assert response.status_code == 500
@@ -123,9 +123,9 @@ def tpl_renderer() -> Template:
     ),
 )
 def test_mako_url_for_static_asset(
-    template_dir: Path, tmp_path: Path, builtin: str, expected_status: int, expected_text: Optional[str]
+    tmp_path: Path, builtin: str, expected_status: int, expected_text: Optional[str]
 ) -> None:
-    template_config = TemplateConfig(engine=MakoTemplateEngine, directory=template_dir)
+    template_config = TemplateConfig(engine=MakoTemplateEngine, directory=tmp_path)
 
     @get(path="/", name="tpl_renderer")
     def tpl_renderer() -> Template:
@@ -136,7 +136,7 @@ def tpl_renderer() -> Template:
         template_config=template_config,
         static_files_config=[StaticFilesConfig(path="/static/css", directories=[tmp_path], name="css")],
     ) as client:
-        Path(template_dir / "tpl.html").write_text(builtin)
+        Path(tmp_path / "tpl.html").write_text(builtin)
 
         response = client.get("/")
         assert response.status_code == expected_status
@@ -153,8 +153,8 @@ def tpl_renderer() -> Template:
         ("${url_for('non-existent-route')}", HTTP_500_INTERNAL_SERVER_ERROR, None),
     ),
 )
-def test_mako_url_for(template_dir: Path, builtin: str, expected_status: int, expected_text: Optional[str]) -> None:
-    template_config = TemplateConfig(engine=MakoTemplateEngine, directory=template_dir)
+def test_mako_url_for(tmp_path: Path, builtin: str, expected_status: int, expected_text: Optional[str]) -> None:
+    template_config = TemplateConfig(engine=MakoTemplateEngine, directory=tmp_path)
 
     @get(path="/")
     def tpl_renderer() -> Template:
@@ -172,7 +172,7 @@ def complex_handler() -> None:
         route_handlers=[simple_handler, complex_handler, tpl_renderer], template_config=template_config
     ) as client:
         # missing route params should cause 500 err
-        Path(template_dir / "tpl.html").write_text(builtin)
+        Path(tmp_path / "tpl.html").write_text(builtin)
         response = client.get("/")
         assert response.status_code == expected_status
         if expected_text:
diff --git a/tests/template/test_config.py b/tests/unit/test_template/test_config.py
similarity index 74%
rename from tests/template/test_config.py
rename to tests/unit/test_template/test_config.py
--- a/tests/template/test_config.py
+++ b/tests/unit/test_template/test_config.py
@@ -7,9 +7,9 @@
     from pathlib import Path
 
 
-def test_pytest_config_caches_engine_instance(template_dir: "Path") -> None:
+def test_pytest_config_caches_engine_instance(tmp_path: "Path") -> None:
     config = TemplateConfig(
-        directory=template_dir,
+        directory=tmp_path,
         engine=JinjaTemplateEngine,
     )
     assert config.engine_instance is config.engine_instance
diff --git a/tests/template/test_context.py b/tests/unit/test_template/test_context.py
similarity index 88%
rename from tests/template/test_context.py
rename to tests/unit/test_template/test_context.py
--- a/tests/template/test_context.py
+++ b/tests/unit/test_template/test_context.py
@@ -18,8 +18,8 @@
         (MakoTemplateEngine, 'path: ${request.scope["path"]}', "path: /"),
     ),
 )
-def test_request_is_set_in_context(engine: Any, template: str, expected: str, template_dir: Path) -> None:
-    Path(template_dir / "abc.html").write_text(template)
+def test_request_is_set_in_context(engine: Any, template: str, expected: str, tmp_path: Path) -> None:
+    Path(tmp_path / "abc.html").write_text(template)
 
     @get(path="/", media_type=MediaType.HTML)
     def handler() -> Template:
@@ -28,7 +28,7 @@ def handler() -> Template:
     with create_test_client(
         route_handlers=[handler],
         template_config=TemplateConfig(
-            directory=template_dir,
+            directory=tmp_path,
             engine=engine,
         ),
     ) as client:
diff --git a/tests/template/test_csrf_token.py b/tests/unit/test_template/test_csrf_token.py
similarity index 85%
rename from tests/template/test_csrf_token.py
rename to tests/unit/test_template/test_csrf_token.py
--- a/tests/template/test_csrf_token.py
+++ b/tests/unit/test_template/test_csrf_token.py
@@ -22,8 +22,8 @@
         (MakoTemplateEngine, "${csrf_token()}"),
     ),
 )
-def test_csrf_token(engine: Any, template: str, template_dir: Path) -> None:
-    Path(template_dir / "abc.html").write_text(template)
+def test_csrf_token(engine: Any, template: str, tmp_path: Path) -> None:
+    Path(tmp_path / "abc.html").write_text(template)
 
     @get(path="/", media_type=MediaType.HTML)
     def handler() -> Template:
@@ -34,7 +34,7 @@ def handler() -> Template:
     with create_test_client(
         route_handlers=[handler],
         template_config=TemplateConfig(
-            directory=template_dir,
+            directory=tmp_path,
             engine=engine,
         ),
         csrf_config=csrf_config,
@@ -50,8 +50,8 @@ def handler() -> Template:
         (MakoTemplateEngine, "${csrf_input}"),
     ),
 )
-def test_csrf_input(engine: Any, template: str, template_dir: Path) -> None:
-    Path(template_dir / "abc.html").write_text(template)
+def test_csrf_input(engine: Any, template: str, tmp_path: Path) -> None:
+    Path(tmp_path / "abc.html").write_text(template)
     token = {"value": ""}
 
     @get(path="/", media_type=MediaType.HTML)
@@ -64,7 +64,7 @@ def handler(scope: Scope) -> Template:
     with create_test_client(
         route_handlers=[handler],
         template_config=TemplateConfig(
-            directory=template_dir,
+            directory=tmp_path,
             engine=engine,
         ),
         csrf_config=csrf_config,
diff --git a/tests/template/test_template.py b/tests/unit/test_template/test_template.py
similarity index 82%
rename from tests/template/test_template.py
rename to tests/unit/test_template/test_template.py
--- a/tests/template/test_template.py
+++ b/tests/unit/test_template/test_template.py
@@ -28,7 +28,7 @@ def invalid_path() -> Template:
         assert response.json() == {"detail": "Template engine is not configured", "status_code": 500}
 
 
-def test_engine_passed_to_callback(template_dir: "Path") -> None:
+def test_engine_passed_to_callback(tmp_path: "Path") -> None:
     received_engine: Optional[JinjaTemplateEngine] = None
 
     def callback(engine: JinjaTemplateEngine) -> None:
@@ -38,7 +38,7 @@ def callback(engine: JinjaTemplateEngine) -> None:
     app = Litestar(
         route_handlers=[],
         template_config=TemplateConfig(
-            directory=template_dir,
+            directory=tmp_path,
             engine=JinjaTemplateEngine,
             engine_callback=callback,
         ),
@@ -49,8 +49,8 @@ def callback(engine: JinjaTemplateEngine) -> None:
 
 
 @pytest.mark.parametrize("engine", (JinjaTemplateEngine, MakoTemplateEngine))
-def test_engine_instance(engine: Type["TemplateEngineProtocol"], template_dir: "Path") -> None:
-    engine_instance = engine(template_dir)
+def test_engine_instance(engine: Type["TemplateEngineProtocol"], tmp_path: "Path") -> None:
+    engine_instance = engine(tmp_path)
     if isinstance(engine_instance, JinjaTemplateEngine):
         assert engine_instance.engine.autoescape is True
 
@@ -62,21 +62,21 @@ def test_engine_instance(engine: Type["TemplateEngineProtocol"], template_dir: "
 
 
 @pytest.mark.parametrize("engine", (JinjaTemplateEngine, MakoTemplateEngine))
-def test_directory_validation(engine: Type["TemplateEngineProtocol"], template_dir: "Path") -> None:
+def test_directory_validation(engine: Type["TemplateEngineProtocol"], tmp_path: "Path") -> None:
     with pytest.raises(ImproperlyConfiguredException):
         TemplateConfig(engine=engine)
 
 
 @pytest.mark.parametrize("media_type", [MediaType.HTML, MediaType.TEXT, "text/arbitrary"])
-def test_media_type(media_type: Union[MediaType, str], template_dir: Path) -> None:
-    (template_dir / "hello.tpl").write_text("hello")
+def test_media_type(media_type: Union[MediaType, str], tmp_path: Path) -> None:
+    (tmp_path / "hello.tpl").write_text("hello")
 
     @get("/", media_type=media_type)
     def index() -> Template:
         return Template(template_name="hello.tpl")
 
     with create_test_client(
-        [index], template_config=TemplateConfig(directory=template_dir, engine=JinjaTemplateEngine)
+        [index], template_config=TemplateConfig(directory=tmp_path, engine=JinjaTemplateEngine)
     ) as client:
         res = client.get("/")
         assert res.status_code == 200
@@ -100,24 +100,24 @@ def index() -> Template:
     ],
 )
 @pytest.mark.skipif(sys.platform == "win32", reason="mimetypes.guess_types is unreliable on windows")
-def test_media_type_inferred(extension: str, expected_type: MediaType, template_dir: Path) -> None:
+def test_media_type_inferred(extension: str, expected_type: MediaType, tmp_path: Path) -> None:
     tpl_name = "hello" + extension
-    (template_dir / tpl_name).write_text("hello")
+    (tmp_path / tpl_name).write_text("hello")
 
     @get("/")
     def index() -> Template:
         return Template(template_name=tpl_name)
 
     with create_test_client(
-        [index], template_config=TemplateConfig(directory=template_dir, engine=JinjaTemplateEngine)
+        [index], template_config=TemplateConfig(directory=tmp_path, engine=JinjaTemplateEngine)
     ) as client:
         res = client.get("/")
         assert res.status_code == 200
         assert res.headers["content-type"].startswith(expected_type.value)
 
 
-def test_before_request_handler_content_type(template_dir: Path) -> None:
-    template_loc = template_dir / "about.html"
+def test_before_request_handler_content_type(tmp_path: Path) -> None:
+    template_loc = tmp_path / "about.html"
 
     def before_request_handler(_: "Request") -> None:
         template_loc.write_text("before request")
@@ -127,7 +127,7 @@ def index() -> Template:
         return Template(template_name="about.html")
 
     with create_test_client(
-        [index], template_config=TemplateConfig(directory=template_dir, engine=JinjaTemplateEngine)
+        [index], template_config=TemplateConfig(directory=tmp_path, engine=JinjaTemplateEngine)
     ) as client:
         res = client.get("/")
         assert res.status_code == 200
diff --git a/tests/middleware/__init__.py b/tests/unit/test_testing/__init__.py
similarity index 100%
rename from tests/middleware/__init__.py
rename to tests/unit/test_testing/__init__.py
diff --git a/tests/testing/test_async_test_client.py b/tests/unit/test_testing/test_async_test_client.py
similarity index 100%
rename from tests/testing/test_async_test_client.py
rename to tests/unit/test_testing/test_async_test_client.py
diff --git a/tests/testing/test_testing.py b/tests/unit/test_testing/test_request_factory.py
similarity index 69%
rename from tests/testing/test_testing.py
rename to tests/unit/test_testing/test_request_factory.py
--- a/tests/testing/test_testing.py
+++ b/tests/unit/test_testing/test_request_factory.py
@@ -1,24 +1,16 @@
 import json
-from typing import TYPE_CHECKING, Any, Callable, Dict, Union
+from typing import Any, Callable, Dict, Union
 
 import pytest
 from pydantic import BaseModel
 
-from litestar import HttpMethod, Litestar, Request, get, post
+from litestar import HttpMethod, Litestar, get
 from litestar.datastructures import Cookie, MultiDict
 from litestar.enums import ParamType, RequestEncodingType
-from litestar.middleware.session.server_side import ServerSideSessionConfig
-from litestar.stores.base import Store
-from litestar.stores.redis import RedisStore
-from litestar.testing import RequestFactory, TestClient, create_test_client
+from litestar.testing import RequestFactory
 from tests import Pet, PetFactory
 
-if TYPE_CHECKING:
-    from litestar.middleware.session.base import BaseBackendConfig
-    from litestar.types import AnyIOBackend
-
 _DEFAULT_REQUEST_FACTORY_URL = "http://test.org:3000/"
-
 pet = PetFactory.build()
 
 
@@ -196,66 +188,3 @@ async def test_request_factory_post_put_patch(factory: Callable, method: HttpMet
     assert request.headers.get("header1") == "value1"
     body = await request.body()
     assert json.loads(body) == pet.dict()
-
-
-@pytest.fixture()
-def skip_for_trio_redis(
-    session_backend_config: "BaseBackendConfig", test_client_backend: "AnyIOBackend", store: Store
-) -> None:
-    if (
-        isinstance(session_backend_config, ServerSideSessionConfig)
-        and isinstance(store, RedisStore)
-        and test_client_backend == "trio"
-    ):
-        pytest.skip("fakeredis does not always play well with trio, so skip this for now")
-
-
-@pytest.mark.usefixtures("skip_for_trio_redis")
-@pytest.mark.parametrize("with_domain", [False, True])
-def test_test_client_set_session_data(
-    with_domain: bool,
-    session_backend_config: "BaseBackendConfig",
-    test_client_backend: "AnyIOBackend",
-) -> None:
-    session_data = {"foo": "bar"}
-
-    if with_domain:
-        session_backend_config.domain = "testserver.local"
-
-    @get(path="/test")
-    def get_session_data(request: Request) -> Dict[str, Any]:
-        return request.session
-
-    app = Litestar(route_handlers=[get_session_data], middleware=[session_backend_config.middleware])
-
-    with TestClient(app=app, session_config=session_backend_config, backend=test_client_backend) as client:
-        client.set_session_data(session_data)
-        assert session_data == client.get("/test").json()
-
-
-@pytest.mark.usefixtures("skip_for_trio_redis")
-@pytest.mark.parametrize("with_domain", [False, True])
-def test_test_client_get_session_data(
-    with_domain: bool, session_backend_config: "BaseBackendConfig", test_client_backend: "AnyIOBackend", store: Store
-) -> None:
-    session_data = {"foo": "bar"}
-
-    if with_domain:
-        session_backend_config.domain = "testserver.local"
-
-    @post(path="/test")
-    def set_session_data(request: Request) -> None:
-        request.session.update(session_data)
-
-    app = Litestar(
-        route_handlers=[set_session_data], middleware=[session_backend_config.middleware], stores={"session": store}
-    )
-
-    with TestClient(app=app, session_config=session_backend_config, backend=test_client_backend) as client:
-        client.post("/test")
-        assert client.get_session_data() == session_data
-
-
-def test_create_test_client_warns_problematic_domain() -> None:
-    with pytest.warns(UserWarning):
-        create_test_client(base_url="http://testserver", route_handlers=[])
diff --git a/tests/testing/test_sync_test_client.py b/tests/unit/test_testing/test_sync_test_client.py
similarity index 100%
rename from tests/testing/test_sync_test_client.py
rename to tests/unit/test_testing/test_sync_test_client.py
diff --git a/tests/unit/test_testing/test_test_client.py b/tests/unit/test_testing/test_test_client.py
new file mode 100644
--- /dev/null
+++ b/tests/unit/test_testing/test_test_client.py
@@ -0,0 +1,76 @@
+from typing import TYPE_CHECKING, Any, Dict
+
+import pytest
+
+from litestar import Litestar, Request, get, post
+from litestar.middleware.session.server_side import ServerSideSessionConfig
+from litestar.stores.base import Store
+from litestar.stores.redis import RedisStore
+from litestar.testing import TestClient
+
+if TYPE_CHECKING:
+    from litestar.middleware.session.base import BaseBackendConfig
+    from litestar.types import AnyIOBackend
+
+
+@pytest.fixture()
+def skip_for_trio_redis(
+    session_backend_config: "BaseBackendConfig", test_client_backend: "AnyIOBackend", store: Store
+) -> None:
+    if (
+        isinstance(session_backend_config, ServerSideSessionConfig)
+        and isinstance(store, RedisStore)
+        and test_client_backend == "trio"
+    ):
+        pytest.skip("fakeredis does not always play well with trio, so skip this for now")
+
+
+@pytest.mark.usefixtures("skip_for_trio_redis")
+@pytest.mark.parametrize("with_domain", [False, True])
+def test_test_client_set_session_data(
+    with_domain: bool,
+    session_backend_config: "BaseBackendConfig",
+    test_client_backend: "AnyIOBackend",
+) -> None:
+    session_data = {"foo": "bar"}
+
+    if with_domain:
+        session_backend_config.domain = "testserver.local"
+
+    @get(path="/test")
+    def get_session_data(request: Request) -> Dict[str, Any]:
+        return request.session
+
+    app = Litestar(route_handlers=[get_session_data], middleware=[session_backend_config.middleware])
+
+    with TestClient(app=app, session_config=session_backend_config, backend=test_client_backend) as client:
+        client.set_session_data(session_data)
+        assert session_data == client.get("/test").json()
+
+
+@pytest.mark.usefixtures("skip_for_trio_redis")
+@pytest.mark.parametrize("with_domain", [False, True])
+def test_test_client_get_session_data(
+    with_domain: bool, session_backend_config: "BaseBackendConfig", test_client_backend: "AnyIOBackend", store: Store
+) -> None:
+    session_data = {"foo": "bar"}
+
+    if with_domain:
+        session_backend_config.domain = "testserver.local"
+
+    @post(path="/test")
+    def set_session_data(request: Request) -> None:
+        request.session.update(session_data)
+
+    app = Litestar(
+        route_handlers=[set_session_data], middleware=[session_backend_config.middleware], stores={"session": store}
+    )
+
+    with TestClient(app=app, session_config=session_backend_config, backend=test_client_backend) as client:
+        client.post("/test")
+        assert client.get_session_data() == session_data
+
+
+def test_create_test_client_warns_problematic_domain() -> None:
+    with pytest.warns(UserWarning):
+        TestClient(app=Litestar(), base_url="http://testserver")
diff --git a/tests/middleware/session/__init__.py b/tests/unit/test_types/__init__.py
similarity index 100%
rename from tests/middleware/session/__init__.py
rename to tests/unit/test_types/__init__.py
diff --git a/tests/types/test_protocols.py b/tests/unit/test_types/test_protocols.py
similarity index 100%
rename from tests/types/test_protocols.py
rename to tests/unit/test_types/test_protocols.py
diff --git a/tests/test_typing.py b/tests/unit/test_typing.py
similarity index 99%
rename from tests/test_typing.py
rename to tests/unit/test_typing.py
--- a/tests/test_typing.py
+++ b/tests/unit/test_typing.py
@@ -6,7 +6,8 @@
 from typing_extensions import Annotated
 
 from litestar.typing import ParsedType
-from tests.utils.test_signature import T, _check_parsed_type, parsed_type_int, test_type_hints
+
+from .test_utils.test_signature import T, _check_parsed_type, parsed_type_int, test_type_hints
 
 
 @pytest.mark.parametrize(
diff --git a/tests/openapi/__init__.py b/tests/unit/test_utils/__init__.py
similarity index 100%
rename from tests/openapi/__init__.py
rename to tests/unit/test_utils/__init__.py
diff --git a/tests/utils/test_dataclass.py b/tests/unit/test_utils/test_dataclass.py
similarity index 100%
rename from tests/utils/test_dataclass.py
rename to tests/unit/test_utils/test_dataclass.py
diff --git a/tests/utils/test_helpers.py b/tests/unit/test_utils/test_helpers.py
similarity index 100%
rename from tests/utils/test_helpers.py
rename to tests/unit/test_utils/test_helpers.py
diff --git a/tests/utils/test_path.py b/tests/unit/test_utils/test_path.py
similarity index 100%
rename from tests/utils/test_path.py
rename to tests/unit/test_utils/test_path.py
diff --git a/tests/utils/test_predicates.py b/tests/unit/test_utils/test_predicates.py
similarity index 76%
rename from tests/utils/test_predicates.py
rename to tests/unit/test_utils/test_predicates.py
--- a/tests/utils/test_predicates.py
+++ b/tests/unit/test_utils/test_predicates.py
@@ -1,7 +1,10 @@
 from collections import defaultdict, deque
+from functools import partial
 from inspect import Signature
 from typing import (
     Any,
+    AsyncGenerator,
+    Callable,
     ClassVar,
     DefaultDict,
     Deque,
@@ -24,7 +27,7 @@
 
 from litestar import Response, get
 from litestar.pagination import CursorPagination
-from litestar.utils import is_any, is_class_and_subclass, is_optional_union, is_union
+from litestar.utils import is_any, is_async_callable, is_class_and_subclass, is_optional_union, is_union
 from litestar.utils.predicates import (
     is_class_var,
     is_generic,
@@ -200,3 +203,58 @@ def test_is_optional_union(value: Any, expected: bool) -> None:
 )
 def test_is_class_var(value: Any, expected: bool) -> None:
     assert is_class_var(value) is expected
+
+
+class AsyncTestCallable:
+    async def __call__(self, param1: int, param2: int) -> None:
+        ...
+
+    async def method(self, param1: int, param2: int) -> None:
+        ...
+
+
+async def async_generator() -> AsyncGenerator[int, None]:
+    yield 1
+
+
+class SyncTestCallable:
+    def __call__(self, param1: int, param2: int) -> None:
+        ...
+
+    def method(self, param1: int, param2: int) -> None:
+        ...
+
+
+async def async_func(param1: int, param2: int) -> None:
+    ...
+
+
+def sync_func(param1: int, param2: int) -> None:
+    ...
+
+
+async_callable = AsyncTestCallable()
+sync_callable = SyncTestCallable()
+
+
+@pytest.mark.parametrize(
+    "c, exp",
+    [
+        (async_callable, True),
+        (sync_callable, False),
+        (async_callable.method, True),
+        (sync_callable.method, False),
+        (async_func, True),
+        (sync_func, False),
+        (lambda: ..., False),
+        (AsyncTestCallable, True),
+        (SyncTestCallable, False),
+        (async_generator, False),
+    ],
+)
+def test_is_async_callable(c: Callable[[int, int], None], exp: bool) -> None:
+    assert is_async_callable(c) is exp
+    partial_1 = partial(c, 1)
+    assert is_async_callable(partial_1) is exp
+    partial_2 = partial(partial_1, 2)
+    assert is_async_callable(partial_2) is exp
diff --git a/tests/utils/test_scope.py b/tests/unit/test_utils/test_scope.py
similarity index 100%
rename from tests/utils/test_scope.py
rename to tests/unit/test_utils/test_scope.py
diff --git a/tests/utils/test_sequence.py b/tests/unit/test_utils/test_sequence.py
similarity index 100%
rename from tests/utils/test_sequence.py
rename to tests/unit/test_utils/test_sequence.py
diff --git a/tests/utils/test_signature.py b/tests/unit/test_utils/test_signature.py
similarity index 100%
rename from tests/utils/test_signature.py
rename to tests/unit/test_utils/test_signature.py
diff --git a/tests/utils/test_sync.py b/tests/unit/test_utils/test_sync.py
similarity index 100%
rename from tests/utils/test_sync.py
rename to tests/unit/test_utils/test_sync.py
diff --git a/tests/utils/test_typing.py b/tests/unit/test_utils/test_typing.py
similarity index 100%
rename from tests/utils/test_typing.py
rename to tests/unit/test_utils/test_typing.py
diff --git a/tests/utils/test_version.py b/tests/unit/test_utils/test_version.py
similarity index 100%
rename from tests/utils/test_version.py
rename to tests/unit/test_utils/test_version.py
diff --git a/tests/utils/__init__.py b/tests/utils/__init__.py
deleted file mode 100644