Repository navigation
Bestiary System Test Plan
Team 5, Sprints 2–3 | Test plan for Bestiary data, unlock progression, discovered-only Library UI and Save/Load integration
This page explains what is tested, why each case exists, the conditions covered, and the expected and actual result. It complements the implementation overview in Bestiary System.
The plan covers these production components and integration points:
-
EnemyConfig/configs/enemies.json: Team 1's single source for combat configuration and enemy descriptions. -
BestiaryEntryandBestiaryEntryView: immutable copies and progress-safe information hiding. -
BestiaryUnlockState: monotonicLOCKED,ENCOUNTERED,DEFEATEDprogression. -
BestiaryService: roster queries, progress updates, snapshots, restore and update events. -
BestiaryTrackingComponent: enemy lifecycle events connected to Bestiary progress. -
EnemyFactory: production attachment of tracking to configured enemies. -
BestiaryDisplay: filters, hidden/revealed details, artwork fallback and live refresh. -
LibraryScreenandBestiaryScreen: navigation into and out of the Bestiary. -
GameStateSnapshotProvider,SaveGameRestoreServiceand save DTOs: persistence and validation.
- Behaviour that can be checked deterministically is covered by JUnit and ships with the implementation.
- Every automated test records the feature contract it protects, not only the method it calls.
- Normal, boundary and invalid-input cases are included where the component accepts external data or state.
- Scene2D appearance, navigation and full player workflows are also tested manually because assertions alone cannot establish that the rendered UI is usable.
- A change is ready for merge only when automated tests pass and all applicable manual cases have an actual result and evidence.
| Item | Required setup |
|---|---|
| Branch | Latest Team 5 integration branch containing the Bestiary changes. |
| Build | Java and Gradle versions specified by the repository. |
| Resolution | Test the normal desktop resolution and one smaller window size. |
| Save data | One fresh slot, one slot with mixed Bestiary progress, and one legacy save without progress.bestiary. |
| Enemy roster | 3 Normal, 2 Elite and 1 Boss from configs/enemies.json. |
Run automated tests from source/:
./gradlew core:test
./gradlew jacocoTestReportOn Windows, use gradlew.bat in place of ./gradlew.
| ID | Component / test | Purpose and reason | Case type | Input or steps | Expected result | Actual result |
|---|---|---|---|---|---|---|
| A01 | BestiaryEntryTest |
Verify enemy combat configuration is copied into an immutable Bestiary definition so later UI reads cannot mutate Team 1 data. | Normal | Build an entry from a valid EnemyConfig. |
Stable ID, name, tier, stats, behaviour, sprite and description match the source. | Pass |
| A02 | BestiaryEntryTest |
Protect fallback behaviour for optional text and missing values. | Boundary | Build with blank description/sprite/behaviour values. | Optional values are normalised without exposing nulls. | Pass |
| A03 | BestiaryEntryTest |
Reject definitions that cannot be tracked safely. | Invalid | Supply blank ID/name or invalid required values. |
IllegalArgumentException is raised before the entry is stored. |
Pass |
| A04 | BestiaryServiceTest |
Confirm the production roster and descriptions are read from one source of truth. This catches an enemy definition without the EnemyConfig.description needed after defeat. |
Integration | Load configs/enemies.json. |
Six entries load: 3 Normal, 2 Elite, 1 Boss; every definition supplies the description exposed after defeat. | Pass |
| A05 | BestiaryServiceTest |
Ensure a direct service read of a locked record cannot leak hidden data. This is defence-in-depth, not the player-visible Library behaviour. | Normal | Query one locked entry before progress is recorded. | The internal view is redacted (???, no sprite, description, stats or behaviour); the UI must not render this view as a list row. |
Pass |
| A06 | BestiaryServiceTest |
Ensure encountering reveals identity only. | State transition | Record ENCOUNTERED. |
Name and sprite are present; description, stats and behaviour remain absent. | Pass |
| A07 | BestiaryServiceTest |
Ensure defeating reveals the complete record. | State transition | Record DEFEATED. |
Description, health, attack, armour and behaviour are present. | Pass |
| ID | Component / test | Purpose and reason | Case type | Input or steps | Expected result | Actual result |
|---|---|---|---|---|---|---|
| A08 | BestiaryServiceTest |
Progress must never regress or emit duplicate work. | Boundary | Encounter twice, defeat, then encounter/defeat again. | Only the first encounter and defeat change state; final state remains DEFEATED. |
Pass |
| A09 | BestiaryServiceTest |
Verify the player-facing tier query excludes every LOCKED record, so undiscovered enemies cannot appear as names, silhouettes, placeholders or rows. |
Normal / boundary | Query every tier in a fresh service, then encounter one Normal and defeat one Boss. | Fresh tiers are empty; only the encountered Normal and defeated Boss occur in their respective discovered lists, in deterministic order. | Pass |
| A10 | BestiaryServiceTest |
Unknown IDs can occur after roster changes and must not crash a save or battle. | Invalid | Record progress for missing and null IDs. | Request is ignored and existing progress is unchanged. | Pass |
| A11 | BestiaryServiceTest |
Save capture must receive a stable read-only snapshot. | Normal | Capture progress after mixed transitions and try to mutate it. | Correct ordered values are returned and mutation is rejected. | Pass |
| A12 | BestiaryServiceTest |
Restore must be atomic and safe across roster versions. | Integration / invalid | Replace with valid entries plus an unknown ID, then try a null state. | Unknown ID is ignored; invalid input throws before existing progress changes. | Pass |
| A13 | BestiaryServiceTest |
Presentation code should refresh once per real transition. | Event | Register a listener, encounter twice and defeat once. | Exactly two events arrive in ENCOUNTERED, DEFEATED order. |
Pass |
| A14 | EventHandlerTest |
Prevent disposed Bestiary screens from remaining subscribed. | Lifecycle | Add and remove the same listener, then trigger the event. | Removed listener receives no call. | Pass |
| ID | Component / test | Purpose and reason | Case type | Input or steps | Expected result | Actual result |
|---|---|---|---|---|---|---|
| A15 | BestiaryTrackingComponentTest |
Prove real combat damage reaches Bestiary progress through the existing enemy lifecycle event. | Integration | Create enemy entity, call create(), then deal lethal damage with takeDamage(). |
Creation records ENCOUNTERED; lethal damage emits enemyDefeated and records DEFEATED. |
Pass |
| A16 | BestiaryTrackingComponentTest |
Prevent trackers with unstable IDs or missing services. | Invalid | Construct with blank ID or null service. | Constructor rejects the dependency. | Pass |
| A17 | EnemyFactoryTest |
Verify production enemies receive tracking rather than only test-built entities. | Integration | Register a service, build via EnemyFactory, create the entity and deal lethal damage. |
Tracker is attached and progress reaches DEFEATED. |
Pass |
| A18 | EnemyFactoryTest |
Keep the final roster and art preload list aligned. | Configuration | Query tier IDs and atlas paths. | Tomb Guardian, Void Knight and Boss Knight appear in the correct tiers and atlas list with no duplicates. | Pass |
| ID | Component / test | Purpose and reason | Case type | Input or steps | Expected result | Actual result |
|---|---|---|---|---|---|---|
| A19 | BestiaryDisplayTest |
Prove the fresh player-facing Library has no locked rows or detail panel. | Normal | Create the display from a service with no discovery progress. | The active tier shows No enemies discovered in this category yet.; no entry is selected and no ??? row, artwork or placeholder is rendered. |
Pass |
| A20 | BestiaryDisplayTest |
Confirm the first encounter immediately adds only that enemy to its tier and retains the defeated-only detail rule. | State transition | Create the display, record an encounter, then inspect the selected record. | The newly encountered enemy is visible by name and artwork; description, stats and behaviour remain hidden. | Pass |
| A21 | BestiaryDisplayTest |
Display complete defeated records consistently and safely degrade missing optional copy. | Normal / boundary | Format a defeated entry with a description, then one without a description. | The normal entry shows description, HP, attack, armour and readable behaviour; the incomplete fixture shows No description available. without crashing. |
Pass |
| A22 | BestiaryDisplayTest |
The open page must refresh each tier's discovered-only list immediately and clean up listeners afterwards. | Event / lifecycle | Create display, switch tiers, record an encounter, dispose display, then record defeat. | Empty categories become populated only for the discovered enemy; no refresh occurs after disposal. | Pass |
| ID | Component / test | Purpose and reason | Case type | Input or steps | Expected result | Actual result |
|---|---|---|---|---|---|---|
| A23 | GameStateSnapshotProviderTest |
Persist discovery progress using stable IDs only. | Normal | Capture a service with mixed unlock states. | Only non-locked entries are written as enemyId plus unlockState. |
Pass |
| A24 | SaveGameRestoreServiceTest |
Restore valid Bestiary progress together with player, deck and map. | Integration | Restore valid mixed progress. | Known entries receive their saved states and omitted entries become locked. | Pass |
| A25 | SaveGameRestoreServiceTest |
A malformed Bestiary section must not partially modify the run. | Invalid | Use blank/duplicate IDs or invalid enum text. | Restore returns INVALID_PROGRESS_STATE; live state remains unchanged. |
Pass |
| A26 | SaveGameRestoreServiceTest |
Roster changes must not make old saves unusable. | Compatibility | Restore a well-formed ID no longer in the current roster. | Unknown ID is ignored safely. | Pass |
| A27 | GameStateSnapshotEndToEndTest |
Verify persistence beyond individual DTO methods. | End-to-end | Save, create fresh runtime objects, load and restore. | Bestiary states after relaunch exactly match the saved states. | Pass |
| A28 | JsonSaveGameRepositoryTest |
Preserve backward compatibility with pre-Bestiary saves. | Compatibility | Load JSON with no progress.bestiary field. |
File loads successfully and all Bestiary records start locked. | Pass |
Record the tester, build/commit, date, actual result and evidence reference for every executed case.
Purpose: verify the complete navigation path and that Back returns to the correct parent screen.
- Launch the game at the Main Menu.
- Select
Bestiaryto open the Library. - Select
Enemy Library. - Confirm the Bestiary screen opens without an error or blank screen.
- Select
Back.
Expected: Main Menu → Library → Bestiary works, and Back returns to Library. Controls remain visible and clickable.
Actual: Pending manual execution.
Purpose: verify undiscovered enemies are absent from the player-visible Library, not represented by question marks or silhouettes.
- Open the Bestiary on a fresh game.
- Select
Normal,EliteandBossin turn. - Inspect each list and detail panel.
- Switch rapidly between all three filters.
- Switch rapidly between all three filters.
Expected: Every tier contains zero visible entries and displays No enemies discovered in this category yet. No ???, silhouette, hidden list row or detail panel is shown. Switching does not duplicate or resize the layout.
Actual: Pending manual execution.
Purpose: confirm the first encounter is the only event needed to add an enemy to the Library, without exposing combat details prematurely.
- Start with a fresh game and open a category; confirm it is empty.
- Enter combat with one known enemy, but leave or return without defeating it.
- Return to the same category in the Library.
- Inspect the list and the newly available detail panel.
Expected: Exactly the encountered enemy appears. Its name and artwork are visible, while description, HP, attack, armour and behaviour remain hidden. All other undiscovered enemies remain absent.
Actual: Pending manual execution.
Purpose: verify the first progression boundary after an enemy entity is created.
- Start a combat containing a known enemy.
- Leave the combat without defeating that enemy.
- Return to the Library and open the same enemy's record; compare it with the empty categories.
Expected: The record is ENCOUNTERED; name and artwork are visible, while description, stats and behaviour remain hidden. Categories with no encounter remain empty.
Actual: Pending manual execution.
Purpose: verify lethal combat damage unlocks the complete record.
- Start combat with a known enemy.
- Deal lethal damage and finish the encounter.
- Open that enemy in the Bestiary.
Expected: The record is DEFEATED and shows the correct description, base HP, attack, armour, behaviour and artwork.
Actual: Pending manual execution.
Purpose: verify Bestiary progress survives a real process restart.
- Produce mixed progress: leave one enemy locked, encounter one and defeat one.
- Save the run to a known slot.
- Exit and relaunch the game.
- Load that slot.
- Open the Bestiary and inspect all three records.
Expected: The encountered and defeated records exactly match the state before exit. Enemies that were still locked remain absent from the Library; no record is accidentally upgraded or reset.
Actual: Pending manual execution.
Purpose: verify the Scene2D layout is usable and missing art fails visibly but safely.
- Open the Bestiary at the normal desktop resolution.
- Resize to a smaller supported window and repeat filter/selection actions.
- On a development build, temporarily configure one encountered enemy with a missing atlas path.
Expected: Text and controls do not overlap or leave the screen. Valid atlases render the correct enemy; a missing atlas uses the fallback/locked-art treatment without crashing.
Actual: Pending manual execution.
Purpose: catch duplicate event listeners, duplicate actors and resource leaks that unit-level formatting tests cannot show visually.
- Open and close the Bestiary at least five times.
- Change filters and select several entries on each visit.
- Continue playing until another Bestiary state changes, then reopen the page.
Expected: Only one UI is visible each time, actions occur once per click, and the latest state is shown without slowdown or duplicate entries.
Actual: Pending manual execution.
- All automated tests pass on the final integration commit.
- Every production Bestiary component is represented by an automated or manual case above.
- M01-M08 have recorded actual results.
- At least one video records the applicable manual Bestiary workflow and its observed result.
- Any failure is linked to an issue or fixed and re-tested before merge.
The pre-Sprint-3 recording predates the discovered-only list rule and must not be used as evidence for M02 or M03. Record a new walkthrough from the current main build after PR #409, identify the tested commit, and attach it here after manual execution.
Status: Pending manual recording.
The recording must show: a fresh empty category; one enemy appearing only after its first encounter; its defeated-only detail reveal; and save/relaunch preservation.