Skip to content

Testing Esmerald Applications

Testing is essential to ensure your Esmerald application behaves as expected. Esmerald provides powerful testing capabilities out of the box using EsmeraldTestClient, which is compatible with pytest and async workflows.


Using EsmeraldTestClient

The EsmeraldTestClient allows you to interact with your application as if it were running, without needing to start a real server.

from esmerald import Esmerald, get
from esmerald.testclient import EsmeraldTestClient

@get("/ping")
def ping() -> dict:
    return {"message": "pong"}

app = Esmerald(routes=[ping])
client = EsmeraldTestClient(app)


def test_ping():
    response = client.get("/ping")
    assert response.status_code == 200
    assert response.json() == {"message": "pong"}

Using Pytest Fixtures

You can define a pytest fixture to reuse the client across multiple test functions.

import pytest

@pytest.fixture
def client():
    return EsmeraldTestClient(app)


def test_ping(client):
    response = client.get("/ping")
    assert response.status_code == 200

Testing with Authentication

If your route depends on an authenticated user, include the token or mocked credentials:

from esmerald import Inject, Injects, get, HTTPException

async def get_current_user():
    return {"username": "admin"}

@get("/me", dependencies={"user": Inject(get_current_user)})
async def get_me(user: dict[str, str] = Injects()) -> dict:
    return user


def test_authenticated():
    client = EsmeraldTestClient(Esmerald(routes=[get_me]))
    response = client.get("/me")
    assert response.status_code == 200
    assert response.json() == {"username": "admin"}

Testing Error Responses

You can test how your application handles errors:

from esmerald import get, HTTPException

@get("/fail")
def fail() -> None:
    raise HTTPException(status_code=418, detail="I'm a teapot")


def test_custom_error():
    client = EsmeraldTestClient(Esmerald(routes=[fail]))
    response = client.get("/fail")
    assert response.status_code == 418
    assert response.json()["detail"] == "I'm a teapot"

Testing Lifespan Events (Startup/Shutdown)

You can test lifecycle hooks by defining handlers and asserting side effects:

called = {"startup": False, "shutdown": False}

async def on_startup():
    called["startup"] = True

async def on_shutdown():
    called["shutdown"] = True

app = Esmerald(routes=[], on_startup=[on_startup], on_shutdown=[on_shutdown])


def test_lifespan():
    with EsmeraldTestClient(app):
        assert called["startup"] is True
    assert called["shutdown"] is True

What's Next?

Now that you know how to test Esmerald APIs:

  • ✅ Use fixtures to isolate tests
  • ✅ Mock dependencies like users or databases
  • ✅ Validate lifecycle events and exceptions

👉 Up next: deployment — learn how to deploy your Esmerald app into production.