Skip to content

test(user): add unit test for the User entity#71

Merged
martinyde merged 1 commit into
developfrom
feature/user-entity-unit-test
Jun 17, 2026
Merged

test(user): add unit test for the User entity#71
martinyde merged 1 commit into
developfrom
feature/user-entity-unit-test

Conversation

@martinydeAI

Copy link
Copy Markdown
Collaborator

Links to issues

None — direct follow-up to a coverage-strategy discussion on
feature/issue-14-assistant-base-entity.
App\Entity\User currently has its lines covered only as a side
effect of the auth-flow integration tests; this PR pins the
behaviour contracts in a focused unit test next to the entity.

Description

Adds tests/Unit/Entity/UserTest.php covering four invariants on
App\Entity\User:

  • getRoles() always includes ROLE_USER and dedupes when the role
    is already present, so a regression that strips the implicit grant
    fails loudly here instead of silently affecting authorisation.
  • getUserIdentifier() returns '' when the email is null and the
    email string otherwise (covers the (string) cast fallback).
  • __serialize() replaces the password with its CRC32C hash, so the
    session never carries the real hash; the test fails if the
    redaction is removed.
  • Setters mutate and return $this.

Pure TestCase: no kernel boot, no DB, no DAMA. Sits next to the
existing AssistantTest under tests/Unit/Entity/.

Screenshot of the result

N/A — test-only change, no UI.

Checklist

  • My code is covered by test cases.
  • My code passes our test (all our tests).
  • My code passes our static analysis suite.
  • My code passes our continuous integration process.

If your code does not pass all the requirements on the checklist you have to add a comment explaining why this change
should be exempt from the list.

Additional comments or questions

The "covered by test cases" box is intentionally unchecked: this PR
is the test — there is no production code change to cover.
Coverage on src/Entity/User.php was already at 100% indirectly via
the auth-flow integration tests; this PR doesn't change the gate
result, only the shape of the coverage so future User fields can
be tested next to the entity rather than via side-channel hunts.


Details - AI specificities

Goal and motivation

User's behaviour was previously verified only by integration tests
of the auth flow (login, password upgrade, session serialisation).
That arrangement covers the lines but couples each User invariant
to a different downstream test — a future regression in
getRoles()'s ROLE_USER guarantee or in __serialize()'s password
redaction would surface as an unrelated auth-flow failure, and any
new User field without a downstream consumer would immediately
drop the coverage gate below 100%.

This PR shifts those invariants into a focused unit test so they
fail loudly at the source and so the next User field can land with
its own test method instead of triggering a coverage scavenger hunt.

Scope

  • New file: tests/Unit/Entity/UserTest.php (six final TestCase
    methods).
  • No production code touched. No fixtures touched. No existing tests
    touched.

Non-goals

  • Does not change any behaviour on App\Entity\User.
  • Does not change the coverage gate threshold (already 100%) or the
    shape of the integration suite.
  • Does not remove or refactor the integration tests that currently
    exercise User as a side effect — they remain valid and are not
    duplicated by these unit-level assertions.

Conventions applied

  • Mirrors tests/Unit/Entity/AssistantTest.php in layout: final class, declare(strict_types=1), App\Tests\Unit\Entity namespace,
    self::assert* style.
  • __serialize() test pins the exact null-byte-prefixed key format
    PHP uses for private-property array casts, since that is the
    serialised payload's contract — changing the property visibility on
    User::$password would break this test, which is the desired
    signal.

Areas needing scrutiny

  • The __serialize() test asserts both that the password key holds
    the CRC32C hash and that no value in the serialised array equals
    the original input. The second assertion is the defence-in-depth
    bit: even if the property structure changes, the test still catches
    a regression that re-introduces the plaintext into the session.

Follow-up work intentionally out of scope

  • The asymmetric question of whether Assistant should keep its full
    getter/setter surface or be pruned (YAGNI) was raised in the
    discussion but is deliberately not bundled here.

Related

Covers the four behaviour contracts on App\Entity\User that today are
only verified as side effects of the auth-flow integration tests:

- getRoles() always includes ROLE_USER and dedupes when the role is
  already present, so a regression that strips the implicit grant
  breaks visibly here instead of silently affecting authorisation.
- getUserIdentifier() returns '' when email is null and the email
  string otherwise.
- __serialize() replaces the password with its CRC32C hash so the
  session never carries the real hash; the test fails loudly if the
  redaction is removed.
- Setters mutate and return $this.

Pins each invariant in a focused test so future User fields can land
with their own test method right next to the entity instead of relying
on whichever integration test happens to hit the new lines.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Martin Yde Granath <yde001@gmail.com>
@martinyde martinyde requested a review from tuj June 17, 2026 07:37
@martinyde martinyde merged commit 149cac6 into develop Jun 17, 2026
3 of 4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants