Skip to content

Bestiary System Test Plan

Luqishu Wu–––– edited this page Oct 7, 2026 · 5 revisions

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.

Scope

The plan covers these production components and integration points:

  • EnemyConfig / configs/enemies.json: Team 1's single source for combat configuration and enemy descriptions.
  • BestiaryEntry and BestiaryEntryView: immutable copies and progress-safe information hiding.
  • BestiaryUnlockState: monotonic LOCKED, ENCOUNTERED, DEFEATED progression.
  • 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.
  • LibraryScreen and BestiaryScreen: navigation into and out of the Bestiary.
  • GameStateSnapshotProvider, SaveGameRestoreService and save DTOs: persistence and validation.

Test Policy

  1. Behaviour that can be checked deterministically is covered by JUnit and ships with the implementation.
  2. Every automated test records the feature contract it protects, not only the method it calls.
  3. Normal, boundary and invalid-input cases are included where the component accepts external data or state.
  4. Scene2D appearance, navigation and full player workflows are also tested manually because assertions alone cannot establish that the rendered UI is usable.
  5. A change is ready for merge only when automated tests pass and all applicable manual cases have an actual result and evidence.

Environment

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 jacocoTestReport

On Windows, use gradlew.bat in place of ./gradlew.

Automated Test Cases

Definitions and Safe Views

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

Progress and Events

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

Enemy Lifecycle Integration

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

Bestiary UI

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

Save, Restore and Compatibility

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

Manual Test Cases

Record the tester, build/commit, date, actual result and evidence reference for every executed case.

M01: Open and Return From the Bestiary

Purpose: verify the complete navigation path and that Back returns to the correct parent screen.

  1. Launch the game at the Main Menu.
  2. Select Bestiary to open the Library.
  3. Select Enemy Library.
  4. Confirm the Bestiary screen opens without an error or blank screen.
  5. Select Back.

Expected: Main Menu → Library → Bestiary works, and Back returns to Library. Controls remain visible and clickable.

Actual: Pending manual execution.

M02: Fresh-Run Tier Filters and Empty States

Purpose: verify undiscovered enemies are absent from the player-visible Library, not represented by question marks or silhouettes.

  1. Open the Bestiary on a fresh game.
  2. Select Normal, Elite and Boss in turn.
  3. Inspect each list and detail panel.
  4. Switch rapidly between all three filters.
  5. 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.

M03: First Encounter Adds One Record

Purpose: confirm the first encounter is the only event needed to add an enemy to the Library, without exposing combat details prematurely.

  1. Start with a fresh game and open a category; confirm it is empty.
  2. Enter combat with one known enemy, but leave or return without defeating it.
  3. Return to the same category in the Library.
  4. 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.

M04: Encountered Record

Purpose: verify the first progression boundary after an enemy entity is created.

  1. Start a combat containing a known enemy.
  2. Leave the combat without defeating that enemy.
  3. 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.

M05: Defeated Record

Purpose: verify lethal combat damage unlocks the complete record.

  1. Start combat with a known enemy.
  2. Deal lethal damage and finish the encounter.
  3. 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.

M06: Save, Relaunch and Restore Progress

Purpose: verify Bestiary progress survives a real process restart.

  1. Produce mixed progress: leave one enemy locked, encounter one and defeat one.
  2. Save the run to a known slot.
  3. Exit and relaunch the game.
  4. Load that slot.
  5. 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.

M07: Layout and Artwork Fallback

Purpose: verify the Scene2D layout is usable and missing art fails visibly but safely.

  1. Open the Bestiary at the normal desktop resolution.
  2. Resize to a smaller supported window and repeat filter/selection actions.
  3. 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.

M08: Repeated Navigation and Listener Cleanup

Purpose: catch duplicate event listeners, duplicate actors and resource leaks that unit-level formatting tests cannot show visually.

  1. Open and close the Bestiary at least five times.
  2. Change filters and select several entries on each visit.
  3. 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.

Exit Criteria

  • 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.

Video Evidence

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.

V01: Sprint 3 Discovered-Only Bestiary Demonstration

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.

Table of Contents

Home

Game Engine

Getting Started

Entities and Components

Service Locator

Loading Resources

Logging

Unit Testing

Debug Terminal

Input Handling

UI

Animations

Audio

AI

Physics

Game Screens and Areas

Terrain

Concurrency & Threading

Settings

Encounters
Tutorials and Contextual Help (Team 2)
Cards (Team 6)
Story (Team 6)
Level design, battle system, turn order, spawn (Team 3)
Cards, Save/Load & Bestiary (Team 5)
Rewards and Battle Settlement (Team 7)

Troubleshooting

MacOS Setup Guide

Clone this wiki locally