Training Grounds Test Plan - UQcsse3200/2026-studio-4 GitHub Wiki

Overview

This test plan covers the training grounds (Training Grounds):

  • The teleport offer โ€” TeleportMenu (what the player is asked, controls lock, confirm, decline, mash protection) and its keyboard handler, built on the shared ModalMenuInputComponent.
  • The practice props โ€” TrainingDummyComponent (heal after every hit, never die, held still), PropInteractableComponent (range, prompt, indicator) and DodgeCannonComponent (firing, hits, dodges, frozen time).
  • The temporary loadout โ€” TrainingLoadoutComponent, which enchants every weapon on entry, lends consumables and puts both back on leaving.
  • The prop manager's tolerance of bad prop definitions โ€” TutorialPropManagerComponent.
  • Prop assets โ€” TutorialPropFactory (icons for every stand item, every texture exists).
  • Moving the player โ€” RoomLoader.getEntrySpawn and the choice between createRoom and createTrainingRoom.
  • The shipped data โ€” the tutorialRoom in rooms.json, the two Old Sage definitions in friendlyNpcs.json and the notice board dialogues: props sit on open floor, every sign reads a real dialogue, every stand lends a real item with an icon, and both Sages point at valid entry points.
  • The rule that only training grounds may have props, enforced by WorldConfig.validate.

The training grounds and the Old Sage are deliberately separate things: the Sage is an Interactable NPC with a teleportOffer; the room is an ordinary room with a trainingGrounds flag. They are tested together here because the offer is only useful if the room it points at is valid.

Testing is split into automated unit tests (what the code must do) and manual gameplay tests (what the player must see). Every behaviour in the automated plan is enforced by a test in the repository โ€” the test class is named above each table.

Test Environment

  • Unit testing: JUnit 5 and Mockito, run headlessly with the engine's GameExtension. OpenGL is mocked, so the components are tested against plain entities. Time is driven by a mocked GameTime (getDeltaTime) and the teleport menu takes an injectable clock, so nothing sleeps. RoomLoaderTest uses Mockito's static mocking to check which RoomFactory method is called.
  • Game testing: Desktop application.
  • Movement: WASD โ€” Dash: SPACE โ€” Interact / read a board / take an item: E โ€” Attack: J โ€” Heavy attack: K โ€” Weapons: 1 2 3 โ€” Potions: TAB to pick, Q to use โ€” Menu: W S / arrows, ENTER / SPACE / E confirm, ESC / Q stay โ€” Debug terminal: F1
  • Terminal command:
room goto tutorialRoom      # move straight into the training grounds
  • Shipped content: the tutorialRoom (60 ร— 46 tiles) with 5 notice boards, 6 dummies, 5 archery targets, 7 supply stands and 3 cannons; the Old Sage in the hub (tutorialGuide) and in the room (trainingGuide); dialogues tutorial_guide, training_guide and tutorial_sign_controls / _melee / _archery / _supplies / _dodge.
  • Tuned values as shipped: confirm is ignored for 400 ms after the menu opens; a cannon fires every 2.4 s, staggered by 0.8 s, and an orb travels 16 tiles at 3 units per second; an orb within 0.3 units of the player is a hit, and one that passes within 1.1 units without touching is a dodge; a dummy has 9999 health and is healed to full after every hit; a prop can be used within 1.3 units, a Sage within 1.5.

Run the automated tests with:

cd source
./gradlew :core:test

Coverage is written to source/core/build/reports/jacoco/test/html/index.html by:

cd source
./gradlew :core:jacocoTestReport

Coverage

Last verified run: 22 Oct 2026 on main (705de3df, containing PR #352) โ€” 2725 tests, 0 failures, 0 skipped project-wide, of which 78 tests across 10 classes were added for the training grounds.

Quality Gate Coverage

Reference: SonarCloud project overview ยท SonarCloud analysis of PR #352 (0 open issues, 0.0% duplication on new code at the time of merging)

The badges above are project-wide. The figures below are the training grounds code only, from a local JaCoCo run of the revision above.

Per-file coverage

File Lines Line coverage Branch coverage Method coverage
components/tutorial/TrainingDummyComponent.java 15 100.0% 50.0% 100.0%
components/tutorial/TrainingLoadoutComponent.java 56 96.4% 78.1% 100.0%
components/tutorial/DodgeCannonComponent.java 60 86.7% 81.2% 75.0%
components/tutorial/PropInteractableComponent.java 20 90.0% 100.0% 85.7%
components/maingame/TeleportMenu.java 56 91.1% 96.2% 86.7%
components/maingame/ModalMenuInputComponent.java 25 100.0% 84.6% 100.0%
components/maingame/ModalMenuDisplay.java (shared with Hecate's menu) 61 96.7% 85.7% 84.6%
components/maingame/KeyboardTeleportMenuInputComponent.java 4 50.0% โ€” 50.0%
components/rooms/configs/PropSpawnConfig.java 9 100.0% โ€” 100.0%
components/tutorial/TutorialPropManagerComponent.java 119 24.4% 17.6% 40.9%
entities/factories/TutorialPropFactory.java 42 23.8% 50.0% 38.5%
components/maingame/TeleportMenuDisplay.java 27 0.0% 0.0% 0.0%
components/tutorial/DamagePopupDisplay.java 29 0.0% 0.0% 0.0%
components/tutorial/FloatingIconComponent.java 18 0.0% 0.0% 0.0%

Existing files that were changed. These figures are for the whole file, so they include code this feature did not touch:

File Lines Line coverage Branch coverage Method coverage
components/rooms/configs/WorldConfig.java (new: props only in training grounds) 42 95.2% 77.3% 100.0%
entities/configs/InteractableNpcConfigs.java (new: teleportOffer validation) 33 100.0% 77.8% 100.0%
entities/configs/InteractableNpcConfig.java (new: TeleportOffer) 17 100.0% 75.0% 100.0%
components/maingame/AbilityMenuDisplay.java (now a ModalMenuDisplay) 58 94.8% 75.0% 100.0%
rooms/RoomSelector.java (new: teleport, propInteract) 89 59.6% 50.0% 60.0%
rooms/RoomLoader.java (new: getEntrySpawn, buildRoom) 56 32.1% 36.8% 38.5%
entities/factories/RoomFactory.java (new: createTrainingRoom) 55 1.8% 0.0% 10.0%

Aggregate across the 9 logic classes (the first nine rows above; JaCoCo, source/core/build/reports/jacoco/test/html/index.html):

Counter Covered Missed Coverage
Instructions 1115 57 95.1%
Branches 94 17 84.7%
Lines 285 21 93.1%
Methods 65 8 89.0%
Classes 11 0 100.0%

Aggregate across all 14 training grounds classes, including the prop manager, the factory and the three classes that draw with OpenGL:

Counter Covered Missed Coverage
Instructions 1349 945 58.8%
Branches 107 92 53.8%
Lines 324 217 59.9%
Methods 79 45 63.7%
Classes 13 3 81.2%

The logic is at about 93% line coverage. The overall figure is lower because TutorialPropManagerComponent, TutorialPropFactory and the three display classes need a real terrain, textures or an OpenGL context, and are covered by the manual plan below. The uncovered lines in the logic classes are listed under Known coverage gaps.

Tests per class

Test class Tests
TrainingGroundsConfigTest 15
TeleportMenuTest 12
TrainingLoadoutComponentTest 12
DodgeCannonComponentTest 8
KeyboardTeleportMenuInputComponentTest 6
PropInteractableComponentTest 6
RoomLoaderTest (7 in the class; 6 added for this feature) 6
TrainingDummyComponentTest 5
TutorialPropManagerComponentTest 4
TutorialPropFactoryTest 4
Total added 78

Automated Unit Test Plan

The teleport offer

TeleportMenuTest

The menu holds no UI or libGDX state, so the whole flow โ€” open, choose, confirm, close โ€” is tested directly with a player that has real PlayerActions and a hand-moved clock.

Test Purpose Expected Result
shouldStartClosed Build the menu. Closed, no offer, controls not locked.
shouldOpenWhenAnNpcWithAnOfferFinishes Send INTERACTION_FINISHED for an NPC whose config has a teleportOffer. The menu opens on that offer with going ahead highlighted, and teleportMenuOpened fires once.
shouldIgnoreNpcsWithoutAnOffer Finish an NPC with no offer, a null NPC and a bare entity. The menu stays shut and no event fires.
shouldLockControlsWhileOpenAndReleaseThemOnClose Open, then close. Controls are locked while open and released on close, with opened then closed fired.
shouldNotOpenTwice Open a second offer while one is showing. Returns false; only one opened event.
shouldRequestTheTeleportWhenConfirmed Confirm the first row after the grace period. teleportToRoom is sent with the offer's room and entry point, the menu closes, and controls are already released so the player arrives free to move.
shouldStayPutWhenTheDeclineRowIsConfirmed Move to the second row and confirm. No teleport request; the menu closes.
shouldIgnoreAConfirmMashedStraightAfterOpening Confirm immediately after opening, then after 400 ms. The early press does nothing โ€” the menu stays open and nothing is sent โ€” and the later press goes ahead. This is the guard against a press meant for the Sage's last line also accepting the offer.
shouldWrapTheSelectionAtBothEnds Move down twice and up once. The highlight wraps: row 2, row 1, row 2.
shouldHighlightGoingAheadAgainOnEveryOpen Move to the decline row, close, reopen. Going ahead is highlighted again.
shouldDoNothingWhileShut Move, confirm and close on a shut menu. Nothing happens, no events, no request.
shouldCloseWhenThePlayerDies Trigger entityDied with the menu open. It closes and the control lock is released, so dying cannot strand the lock.

KeyboardTeleportMenuInputComponentTest

The shared ModalMenuInputComponent is tested through the teleport menu's keyboard handler. Its other subclass, for Hecate's menu, has its own existing tests.

Test Purpose Expected Result
shouldSitAboveTheUiStageAndBelowDialogue Compare priorities. Above the debug terminal and UI stage (10) and below dialogue input (20), so a dialogue always wins and the menu is modal over everything else.
shouldIgnoreEverythingWhileClosed Send keys, a click and a scroll with the menu shut. Nothing is consumed.
shouldSwallowEverythingWhileOpen Send A, D, releases, typed characters, clicks, drags and a scroll while open. All are consumed and the menu stays open, so nothing walks the player around behind it.
shouldMoveTheSelectionWithArrowsAndWasd Press DOWN, UP, S, W. The highlight moves between the two rows each time.
shouldConfirmWithEnterSpaceOrE Open and press ENTER, NUMPAD_ENTER, SPACE, then E. Each requests the teleport and closes the menu.
shouldLeaveWithEscapeOrQ Open and press ESC, then Q. Each closes the menu without a teleport request.

The practice props

TrainingDummyComponentTest

Test Purpose Expected Result
shouldBeToppedUpAfterEveryHit Deal 25 damage. Health is back at its maximum and the dummy is not dead.
shouldReportEachHitWithItsDamageAndRunningTotal Deal 25, then 40. trainingTargetHit fires with (label, 25, 1) then (label, 40, 2), and getHits() is 2.
shouldNeverDieNoMatterHowHardItIsHit Deal one less than its maximum health five times. entityDied never fires and health stays at its maximum.
shouldNotCountZeroDamage Deal 0 damage. No hit counted, no event.
shouldBeHeldStillEveryFrame Update a dummy that has a physics body. The body's velocity is set to zero. A dummy has to be a dynamic body for weapon hitboxes to register on it, so this stops knockback sliding it across the room.

PropInteractableComponentTest

Test Purpose Expected Result
shouldBeInRangeOnlyWithinItsRange Test a player 1.5 and 2.5 units away with a range of 2. In range, then out of range.
shouldMeasureDistanceBetweenCentres A player at (3, 4) from a prop at the origin. Distance is 5.
shouldRunItsActionWithThePlayer Interact. The action runs once with that player.
shouldExposeItsPrompt Read the prompt. It is the text it was built with.
shouldOnlyAnnounceTheIndicatorWhenItChanges Show twice, hide twice. INDICATOR_SHOWN then INDICATOR_HIDDEN, each once.
shouldRefuseMissingPromptOrAction Build with a null prompt, then a null action. Each throws NullPointerException.

DodgeCannonComponentTest

Cannons are built with a plain entity as their orb, so no art is needed, and time is stepped 0.1 s at a time.

Test Purpose Expected Result
shouldFireImmediatelyWhenThereIsNoDelay Update once with no delay. One orb exists.
shouldWaitOutItsDelayBeforeTheFirstShot Give it a 0.5 s delay and step. Nothing before 0.5 s, one orb just after.
shouldFireAgainEveryInterval One-second interval over 2.5 s. Three orbs.
shouldSpawnOrbsAtTheCannonsMouthAndMoveThemDown Fire one and step. It starts centred under the cannon and its y falls.
shouldReportAHitWhenAnOrbReachesThePlayer Put the player dead centre in the lane. One dodgeResult(false).
shouldReportADodgeWhenAnOrbPassesCloseWithoutTouching Put the player beside the lane, close enough to be dodging but not clipped. One dodgeResult(true) once the orb has travelled its range.
shouldIgnoreOrbsThatNeverComeNearThePlayer Put the player far from the lane. No result at all โ€” wandering elsewhere in the room is not a dodge.
shouldNotFireWhileTimeIsStopped Use a clock with a zero delta. No orbs, which is how a dialogue freezes the cannons.

TutorialPropManagerComponentTest

Spawning a real prop needs terrain, so these cover how the manager copes with bad definitions, which is the path that must never stop a room from loading.

Test Purpose Expected Result
shouldSkipAPropWithNoTypeInsteadOfFailingTheRoom Spawn a prop with no type. Skipped without an exception.
shouldSkipASignWithNoDialogue Spawn a sign with no dialogueId. Skipped without an exception.
shouldSkipASupplyStandForAnUnknownItem Spawn stands for an unknown item and for no item. Both skipped without an exception.
shouldFindNothingToUseInARoomWithNoProps Ask a propless room for the nearest prop. null.

TutorialPropFactoryTest

Test Purpose Expected Result
iconPathsAreNamedAfterTheItemId Ask for the icon path of HEALTH_POTION. images/tutorial/icons/health_potion.png.
everyStandItemHasAnIconThatIsLoadedWithTheRoom Check the seven stand items. Each icon is in the room's texture list.
everyPropTextureExistsOnDisk Resolve every prop texture. Every file exists, so a missing sprite fails the build rather than a player.
aStandForAnItemWithoutAnIconIsRefused Build a stand for a gold coin. IllegalArgumentException.

The loadout

TrainingLoadoutComponentTest

A player with real WeaponUpgradeComponent and InventoryComponent enters and leaves a room that lends a health potion and a freeze bomb.

Test Purpose Expected Result
shouldUpgradeEveryWeaponOnEntry Enter the room. The sword, knife and bow are all upgraded.
shouldExplainTheEnchantmentOnEntry Enter the room. One status message, and it mentions heavy attacks.
shouldTakeTheUpgradesBackOnLeaving Enter, then dispose the room. No weapon is upgraded.
shouldKeepUpgradesThePlayerAlreadyBought Own a sword upgrade, enter, leave. The sword is still upgraded; the bow is not.
shouldLendOneCopyAtATime Lend a potion twice. The first succeeds, the second is refused, and the player holds one.
shouldLendAgainOnceTheLentCopyIsUsed Lend, use it, lend again. The second lend succeeds.
shouldTakeLentItemsBackOnLeaving Lend a potion and a bomb, then leave. Both counts are back to zero.
shouldLeavePotionsThePlayerBroughtInAlone Arrive with two potions, lend one, leave. They hold three while inside and exactly two after.
shouldNeverTakeMoreThanWasLent Arrive with one potion, drink it inside, leave. They end with none; nothing is taken that they did not receive.
shouldOnlyLendWhatTheRoomOffers Try to lend a shield. Refused, because no stand in the room offers it.
shouldNotLendBeforeThePlayerHasEntered Lend before RoomCreated. Refused.
shouldRestoreOnlyOnce Leave, add a potion, dispose the component again. The second dispose changes nothing.

Moving the player and choosing the factory

RoomLoaderTest

Only the six tests added for this feature are listed. The seventh, shouldValidateWorldOnContructor, was already in the class.

Test Purpose Expected Result
shouldLandATeleportAtTheNamedEntryPoint Ask for the entry point gate of room yard. Its tile position.
shouldRefuseATeleportToAnUnknownEntryPoint Ask for an entry point that does not exist. IllegalArgumentException.
shouldRefuseATeleportToAnUnknownRoom Ask for a room that does not exist. IllegalArgumentException.
shouldBuildTrainingGroundsWithTheTrainingFactory Load a room flagged trainingGrounds. createTrainingRoom is used and createRoom is never called.
shouldBuildEveryOtherRoomWithTheUsualFactory Load an ordinary room twice. createRoom is used and createTrainingRoom is never called.
shouldChooseTheFactoryForTheStartingRoomToo Load the starting room. It goes through the same choice.

Shipped Data

TrainingGroundsConfigTest

These load the real shipped JSON, so a broken room, prop or Sage fails the build rather than a player.

Test Purpose Expected Result
worldStillValidatesWithTheRoomAdded Validate the world and the NPC definitions. Neither throws.
roomIsAPracticeSpaceWithNoEnemiesOrExits Inspect tutorialRoom. Flagged trainingGrounds, no enemies (they would block clearing and drop loot), no exits, and dungeonId is null so no dungeon timer starts.
otherRoomsAreNotTrainingGrounds Inspect every other room. None is flagged and none has props.
mapGridMatchesItsDeclaredSize Compare the grid to mapWidth and mapHeight. Every row is the declared width and there are the declared number of rows.
bothSagesOfferToTeleportToEachOther Read both Sages' offers. The hub Sage goes to tutorialRoom, the training Sage to selection, and each entry point exists.
trainingSageStandsInTheRoomAndHubSageStaysInTheHub Look at the NPC spawns. The training Sage is only in the room and the hub Sage only in the hub.
arrivalsLandOnFloorInBothDirections Apply the spawn offset (+2, โˆ’2) to fromSage and fromTutorial. Both land on floor, not in a wall.
everyPropAndNpcStandsOnOpenFloorInsideTheMap Check every prop and NPC position. Inside the map, on floor and not on a wall or crate, and no two on one tile.
roomTeachesEveryMechanic Count props by type. There is at least one of every PropType.
everySignReadsARealDialogue Load each sign's dialogue. It loads, has lines, every speaker is defined and every portrait exists.
everySupplyStandLendsARealConsumableWithAnIcon Check each stand. A real item with an icon on disk, no duplicates, and both freeze bombs and burn vials are on offer.
cannonsAreConfiguredToFireAtAReadableRate Check each cannon. At least one second between shots, a positive range and a non-negative delay.
trainingGuideDialogueLoads Load the training Sage's dialogue. It loads and has lines.
propsAreOnlyAllowedInTrainingGrounds Give the hub the room's props, validate, then flag the hub. Validation fails, then passes once the hub is a training ground.
teleportOffersNeedADestination Validate an NPC with no offer, an empty offer, a room only, then room and entry point. Valid, rejected, rejected, valid.

Manual Gameplay Test Plan

Setup for every test below: run the game (cd source && ./gradlew :desktop:run), start a run and talk to the Old Sage in the hub to reach the training grounds. To skip the dialogue, open the debug terminal (F1) and run room goto tutorialRoom.

Getting there and back

Test Steps Expected Result
Offer appears In the hub press E next to the Old Sage and advance to the last line. After the final line a panel titled Training Grounds asks the question, with two rows, the first highlighted, and a key hint along the bottom.
Mashing is safe Mash SPACE through the whole dialogue. The menu opens but is not confirmed by the presses that finished the dialogue.
Choosing Press S then W. The highlight moves and the text of the highlighted row darkens.
Stay Choose Not right now, or press ESC. The panel closes, you stay in the hub and can move again.
Controls locked With the panel open, press A, D, J and I. The player does not move, attack or open the inventory behind the panel.
Go Choose Take me to the training grounds. The room changes, the title Training Grounds shows, you can move straight away and you stand near the second Old Sage.
Enchantment notice Look at the top of the screen on arrival. A message says weapons are enchanted and heavy attacks work.
Music Listen after arriving. The calm hub music keeps playing; the fight music never starts.
Return Press E at the training Sage, advance the dialogue and choose Return to the village. You arrive in the hub beside the original Sage and can move.
Repeat Go there and back a second time. Same result, no stuck controls and no duplicated props.

Notice boards

Test Steps Expected Result
Marker and prompt Walk up to each board. A yellow marker bobs above it and the top right shows Press E โ€” Read and the board's name. Walking away hides both.
Reading Press E at each of the five boards. A dialogue opens with Notice Board as the speaker and the board's portrait, and the world freezes until it ends.
Content Read all five. They cover controls, melee, archery, supplies and dodging, and the keys named in them match the game.
Sage wins Stand where both a board and the Sage are in range. E talks to the Sage, not the board.
No double trigger Press E once at a board. Exactly one dialogue opens.

Melee

Test Steps Expected Result
Damage numbers Face a dummy and press J. A number floats up from the dummy and the status line shows the damage and hit count.
Never dies Hit a dummy 30 times. It never dies or disappears.
Held still Push into a dummy, and hit it while standing next to it. It does not slide.
Heavy attack Press K with the sword, the knife and the bow. The sword spins all the way round, the knife lands a three-hit flurry and the bow fires three arrows. Each works even though you have not bought the upgrade.
Weapon swap Press 1, 2 and 3. The weapon changes and each hits for a different amount.
Dummies in the supplies room Hit a test dummy. Same behaviour; the label is Test Dummy.

Archery

Test Steps Expected Result
Near target Press 3, stand on the red line, face a near target and press J. The arrow hits, a number floats up and the status line says Near Target.
Far target Aim at a far target. The arrow reaches it.
Spread Press K facing a target. Three arrows fire in a spread.
Blocking Line up a far target directly behind a near one. The arrow stops on the near target.
Walls Shoot at a box or a sign. The arrow disappears; it does not pass through.

Supplies

Test Steps Expected Result
Icons Look at the seven stands. Each shows a clear icon of its item, floating above the pedestal, readable from normal play distance.
Marker Stand at a stand. The marker is above the icon, not over it. Prompt reads Press E โ€” Take and the item name.
Take Press E. A message says you took one, and it is in your inventory (and the consumable bar if a slot is free).
Only one Press E again. A message says you already hold one; nothing is added.
Use and retake Use it with TAB and Q, then take another. You can take another once the lent one is used.
Effects Take and use each of the seven. Healing, shield, speed and strength work. A freeze bomb freezes, and a burn vial burns, the test dummies on screen. A magnet potion has its normal effect.
Nothing leaks Take a potion, leave through the Sage, then check the inventory. The lent potion is gone. Potions you owned before are still there.
Brought-in potions Arrive with a health potion, take one, leave. You are back to the one you owned.

Dodge range

Test Steps Expected Result
Orbs fire Walk to the top right. Three cannons fire purple orbs down their lanes, staggered.
Hit Stand in a lane. The orb disappears on touching you, the status line says you were clipped, and your health does not change.
Dodge Dash (SPACE) across a lane as an orb arrives. The status line says Dodged and the count goes up.
Far away Stay well away from the lanes. No dodge is counted.
Frozen by dialogue Read the Dodge Board while orbs are in flight. The orbs stop while the dialogue is open and carry on afterwards.

Leaving and restoring

Test Steps Expected Result
Upgrades restored Before going, check whether a weapon is upgraded (heavy attack works), then go there and back. Weapons that were not upgraded can no longer heavy attack, and ones you had bought still can.
Terminal entry Run room goto tutorialRoom from the hub and from a dungeon room. You arrive in the training grounds with the same enchantment, and leaving restores it.

Regression: Hecate's menu

Hecate's menu now shares its input and display code with the teleport menu.

Test Steps Expected Result
Looks the same Press E at Hecate and finish her dialogue. The same cream panel, title, two ability rows with the current one marked carried, and a key hint.
Keys Use W / S, ENTER and ESC. Choose, attune and leave work as before, and nothing walks the player behind it.

Known Coverage Gaps

Everything uncovered in the logic classes is listed here. Nothing below is a known defect; each is either untestable without terrain, textures or OpenGL, or a path no shipped content reaches.

Location Uncovered Why
TeleportMenuDisplay, DamagePopupDisplay, FloatingIconComponent The whole classes (0%) They create scene2d actors, read textures and draw with the batch, which need a real OpenGL context; GameExtension mocks GL. Covered by the manual plan above. The behaviour they depend on is tested through TeleportMenu and TrainingDummyComponent.
TutorialPropManagerComponent Spawning, build*, lendItem, onDodgeResult, onInteract, update, updatePrompt, dispose (24%) Spawning a prop needs a TerrainComponent and loaded textures. Only the tolerance of bad definitions is unit tested. The rest is covered by manual tests for boards, stands, dummies and cannons.
TutorialPropFactory Building each prop (the create* methods) They create physics bodies and read textures from the ResourceService. The icon naming, the texture list and the refusal of a stand without an icon are tested.
RoomFactory.createTrainingRoom The whole method It calls createRoom, which builds terrain and needs OpenGL. Which factory is chosen is tested in RoomLoaderTest; the room as a whole is covered by manual testing.
RoomSelector.teleport The method and its scheduling RoomSelector is built around a real room and entity service. The entry point lookup it uses is tested in RoomLoaderTest and the request is tested at the menu.
TeleportMenu(Entity) The public constructor that uses the real clock Tests use the package-private constructor with a hand-moved clock.
TeleportMenu.dispose Closing a menu while the entity is disposed Defensive; close itself is tested.
KeyboardTeleportMenuInputComponent(TeleportMenu) The constructor that takes a menu Tests use the no-argument constructor, which finds the menu on the entity, as the game does.
ModalMenuDisplay draw and getZIndex Drawn by the stage; the rest of the class is covered through Hecate's menu tests.
DodgeCannonComponent The public constructor and dispose Tests inject an orb with no art. Disposing live orbs with the room is checked manually.
DodgeCannonComponent.update The "no time source" branch Defensive; tests always register one.
PropInteractableComponent The constructor that uses the default range Tests pass a range.
TrainingLoadoutComponent The "already applied" guard on a repeated RoomCreated, and the "could not remove" guard Defensive; neither is reachable from the shipped room.

Areas Not Covered by Automated Tests

  • Visual correctness. Nothing asserts a pixel. Whether the icons read clearly, the sprites look right, the damage numbers are legible and the panel lines up is judged manually. The art is placeholder.
  • The room as a whole. No test builds the real room with terrain. That the props are on floor and every reference resolves is tested from the JSON, but the spawn, collision and physics behaviour is only seen in play.
  • Weapons hitting the dummies. The dummy's response to damage is tested; that the sword sweep, the knife flurry and the arrows actually reach it in the physics world is judged manually.
  • Interaction priority and the marker. The rule that the Sage wins over a board, the prompt and the marker are manual tests.
  • Hold-E pickup. E now fires on release so it can double as a hold to collect drops. Props sit downstream of the interact event and are checked manually.
  • Wall-clock timers. The freeze zeroes the shared game time scale; the cannons use that, but timers that read the system clock keep running during a dialogue.
  • Text accuracy. The keys named in the board and Sage dialogues are plain text. A rebinding would not fail a test.
  • Content quality. Writing and tone are not tested.

Related pages