Add comprehensive unit tests for uncovered areas#6
Conversation
Agent-Logs-Url: https://github.com/AldanDev/Notora/sessions/22cc2300-8b7e-4938-90e1-9a50c67f8730 Co-authored-by: Pentusha <1904496+Pentusha@users.noreply.github.com>
Agent-Logs-Url: https://github.com/AldanDev/Notora/sessions/a8913a70-7492-4b98-b1f5-dbd935cdb637 Co-authored-by: Pentusha <1904496+Pentusha@users.noreply.github.com>
Agent-Logs-Url: https://github.com/AldanDev/Notora/sessions/a8913a70-7492-4b98-b1f5-dbd935cdb637 Co-authored-by: Pentusha <1904496+Pentusha@users.noreply.github.com>
Agent-Logs-Url: https://github.com/AldanDev/Notora/sessions/33a5b3b8-01cf-48a0-9764-e1b8b3f13e51 Co-authored-by: Pentusha <1904496+Pentusha@users.noreply.github.com>
Agent-Logs-Url: https://github.com/AldanDev/Notora/sessions/0c9226ce-dcec-448f-9dec-dd4ef561c525 Co-authored-by: Pentusha <1904496+Pentusha@users.noreply.github.com>
…ve_to_column assertions Agent-Logs-Url: https://github.com/AldanDev/Notora/sessions/92bb63bf-07cf-4012-bba6-1fb6dda66289 Co-authored-by: Pentusha <1904496+Pentusha@users.noreply.github.com>
…e passing to _render Agent-Logs-Url: https://github.com/AldanDev/Notora/sessions/8d88a3ea-029a-49eb-9e7a-7eb4399e3242 Co-authored-by: Pentusha <1904496+Pentusha@users.noreply.github.com>
Pentusha
left a comment
There was a problem hiding this comment.
Overall Assessment
Approve with minor nits. This is a solid, well-structured test PR that meaningfully increases coverage (+6 pp) without touching production code. The tests are focused, fast, and exercise edge cases effectively.
Highlights
- Good separation of concerns. Each test file maps cleanly to a single module or mixin.
- Edge-case coverage.
test_utils.pycorrectly tests falsy-but-not-Nonevalues (0,"",[]).test_serializer_mixin.pycovers empty lists, schema overrides, and fallback chains. - Factory tests are thorough.
test_factory.pyvalidates not just happy paths but also theTypeErrorraised when a soft-delete service class is paired with a non-soft-delete repo. - Query-DSL tests are comprehensive. All nine filter operators, sort directions, predicate fields, and error paths are covered. Using PostgreSQL dialect compilation with literal binds makes assertions deterministic.
- No database required. All new tests are pure unit tests, keeping the feedback loop fast.
Minor Issues / Nits
1. ColumnElement type-arg consistency
test_query_dsl_tokens.py already casts to ColumnElement[Any] in two places (fixed in this PR), but the _render helper itself is typed as ColumnElement without a parameter:
def _render(clause: ColumnElement) -> str: # type: ignore[type-arg]Consider aligning it with ColumnElement[Any] and removing the # type: ignore[type-arg] for consistency.
2. v2/enums still uncovered
src/notora/v2/enums/__init__.py and src/notora/v2/enums/base.py remain at 0 % coverage. They are tiny (6 lines total), so a single test file importing and asserting OrderByDirections.ASC.value == "asc" would bring them to 100 % with minimal effort.
3. _make_obj helper in test_serializer_mixin.py
Using types.SimpleNamespace() is clever for from_attributes=True schemas, but it’s worth adding a short comment explaining why it works (no required SQLAlchemy-mapped fields), so future readers don’t assume it’s a general-purpose model mock.
4. Exception test duplication
tests/v1/test_unit/test_enums_and_exceptions.py and tests/v2/test_unit/test_exceptions.py share nearly identical assertions for FKNotFoundError, AlreadyExistsError, and NotFoundError. This is expected because the classes are duplicated across versions, but if the project ever deduplicates them, both files will need updating.
Suggestions for Follow-up PRs
- Cover
m2mmixin branches —src/notora/v2/services/mixins/m2m.pyhas several uncovered rollback / bulk-attach paths. - Cover
v2/enums— trivial 6-line win. - Property-based tests —
hypothesisis already in the lockfile (viaREADME.mdreference). A few property-based tests forPaginationMetaSchema.calculateorvalidate_exclusive_presencecould catch boundary bugs automatically.
Checklist Verification
| Check | Status |
|---|---|
| Lint (ruff, mypy, pyright, stubtest) | ✅ Pass |
| Tests (345/345) | ✅ Pass |
| No production-code changes | ✅ Confirmed |
| Coverage increase | ✅ 84 % → 90 % |
There was a problem hiding this comment.
Pull request overview
Adds broad unit-test coverage for previously under-tested v1/v2 helpers, schemas, exceptions, factories, and service mixins, plus a small typing cleanup in pytest fixtures. This strengthens confidence in core library behavior without changing production APIs.
Changes:
- Adds new v1 unit tests for enums, exceptions, schema helpers, pagination metadata, and validation/time utilities.
- Adds new v2 unit tests for exceptions, factories, query DSL token parsing/building, payload/serializer/updated-by mixins, and base schemas.
- Cleans up pytest fixture typing and updates an existing query-schema test helper for deterministic SQL rendering.
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
tests/v2/test_unit/test_updated_by_mixin.py |
Adds unit coverage for UpdatedByServiceMixin payload injection and error paths. |
tests/v2/test_unit/test_serializer_mixin.py |
Adds serializer mixin tests for schema fallback and error behavior. |
tests/v2/test_unit/test_schemas_base.py |
Adds v2 schema tests for ClientMeta and pagination total clamping. |
tests/v2/test_unit/test_query_dsl_tokens.py |
Adds broad query DSL parser/clause-builder coverage. |
tests/v2/test_unit/test_pydantic_query_schemas.py |
Refactors SQL rendering helper to use a PostgreSQL dialect instance. |
tests/v2/test_unit/test_payload_mixin.py |
Adds _dump_payload unit tests for dict and Pydantic inputs. |
tests/v2/test_unit/test_factory.py |
Adds coverage for repository/service factory helpers and soft-delete variants. |
tests/v2/test_unit/test_exceptions.py |
Adds v2 exception behavior tests. |
tests/v2/conftest.py |
Adds a concrete type annotation for the fixture request object. |
tests/v1/test_unit/test_utils.py |
Adds coverage for time and exclusive-presence validation utilities. |
tests/v1/test_unit/test_schemas_base.py |
Adds v1 schema/helper tests for datetime handling, pagination, filters, and ordering. |
tests/v1/test_unit/test_enums_and_exceptions.py |
Adds v1 enum and exception tests. |
tests/conftest.py |
Adds typing to the custom pytest option hook. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Use pytest.Parser instead of _pytest private import - Rename test to match actual behavior (soft-delete flag + explicit service class) - Rename filter default op test to reflect '=' not 'eq' - Use Mapped[UUID | None] instead of Mapped[object] in updated_by test doubles
Summary
Adds 10 new unit-test files (1,216 lines) covering previously uncovered areas in both
v1andv2APIs. All tests are pure unit tests — no database required — and focus on edge cases, error paths, and fallback behaviour.What’s new
tests/v1/test_unit/test_enums_and_exceptions.pyOrderByDirections,FKNotFoundError,AlreadyExistsError,NotFoundErrortests/v1/test_unit/test_schemas_base.pynormalize_datetime_to_utc,utc_datetime_encoder,datetime_encoder,PaginationMetaSchema,AdminMeta,ClientMeta,Filter,OrderBy,OrFilterGrouptests/v1/test_unit/test_utils.pynow_without_tz,validate_exclusive_presence(including falsy-but-not-Noneedge cases)tests/v2/test_unit/test_exceptions.pyFKNotFoundError,AlreadyExistsError,NotFoundErrortests/v2/test_unit/test_factory.pybuild_repository,build_service,build_service_for_repo— standard & soft-delete variants, custom classes, config propagation, error pathstests/v2/test_unit/test_payload_mixin.py_dump_payloadwithdictand Pydantic-model inputs,exclude_unsetbehaviourtests/v2/test_unit/test_query_dsl_tokens.pyparse_filter_token,parse_sort_token,apply_filter_operator,resolve_to_column,build_filter_clauses,build_sort_clauses,build_query_params— all operators, error paths, predicate fields, empty-token handlingtests/v2/test_unit/test_schemas_base.pyClientMeta,PaginationMetaSchema.calculate(negative-total clamping)tests/v2/test_unit/test_serializer_mixin.pyserialize_one,serialize_many— explicit schema arg, fallback todetail_schema/list_schema, empty-list handling,prefer_list_schemaflagtests/v2/test_unit/test_updated_by_mixin.py_apply_updated_by—actor_idinjection, preservation of existing value, missing-attribute error, custom attribute nameFixes applied
_SoftWidget(SoftDeletableModel)soSoftDeleteRepository.__init__succeeds (models must exposedeleted_at).str(col)with_render(col)(PostgreSQL dialect + literal binds) for deterministic assertions.resolve_to_columnresults toColumnElement[Any]before passing to_render.Anytype parameter toColumnElementcasts intest_query_dsl_tokens.pyto satisfy mypystrict = true.Coverage impact
src/notora/utils/validation.pysrc/notora/v1/exceptions/common.pysrc/notora/v1/schemas/base.pysrc/notora/v2/exceptions/common.pysrc/notora/v2/repositories/query_dsl.pysrc/notora/v2/services/mixins/updated_by.pysrc/notora/v2/services/mixins/payload.pysrc/notora/v2/services/mixins/serializer.pyVerification
make lintpasses (ruff, mypy, pyright, stubtest)make testpasses (345 tests)Follow-up ideas (out of scope)
v2/enums/*is still at 0 % direct coverage — tiny import-level tests could be added.v2/services/mixins/m2m.pyhas several uncovered branches (bulk-attach edge cases, rollback paths).v1/persistence/repos/base.pyandv1/services/base.pyremain at ~70 %; full coverage would require heavy mocking of SQLAlchemy sessions.