Query and value assertions¶
Checks a test makes beyond the values it reads: how many queries a block of code runs, and matchers that compare a value by a rule instead of by equality.
Counting queries: assert_query_count()¶
def capture_queries(using: str | DatabaseClient | None = None) -> AbstractAsyncContextManager[QueryCounter]: ...
def assert_query_count(
expected: int,
*,
using: str | DatabaseClient | None = None,
) -> AbstractAsyncContextManager[QueryCounter]: ...
assert_query_count fails with an AssertionError listing every captured query's SQL text if the block
runs anything other than exactly expected queries — the direct way to pin down a missing
select_related()/prefetch_related() as a test failure instead of discovering it in production.
capture_queries is the lower-level primitive it's built on, for when you want the count/query list
without asserting on it:
async with capture_queries() as counter:
await Book.objects.all().select_related("author")
assert counter.count == 1
QueryCounter (connection_alias: str, count: int, queries: list[str]) updates live as the block
runs, not only once it exits. Every statement counts exactly once — model loads,
values()/values_list(), aggregate(), count()/exists(), writes, raw SQL, each stream() and
each bulk_create(use_copy=True) batch (recorded as COPY <table> (<columns>) FROM STDIN) — even where
one client method internally delegates to another.
Value matchers (hare.contrib.test.conditions)¶
Not re-exported from the top-level hare.contrib.test package — import from the submodule directly:
Usable on the right-hand side of an == comparison, e.g. inside a dict compared against real data in an
assertion:
| Class | Matches |
|---|---|
NotEQ(value) |
Anything not equal to value. |
In(*values) |
Anything that is one of values. |
NotIn(*values) |
Anything that is none of values. |
A matcher of your own derives from Condition (hare.contrib.test.conditions), which keeps its value,
and defines __eq__.