Skip to content

Interactable NPCs Test Plan

Woutermelon edited this page Oct 8, 2026 · 1 revision

Testing plan

Approach

  • Unit tests (JUnit 5 + Mockito) cover each class in isolation, with the most coverage on the sequence state machine and availability rules, where bugs are likely and hard to spot in play.
  • Config tests load the real friendlyNpcs.json and rooms.json, so a bad edit to either fails the build instead of the game.
  • Integration-style unit tests wire real components together on a test entity (interactor + PlayerActions) to check locking end to end without rendering.
  • Manual play testing covers what can't be unit tested: the sprite, indicator, prompt, and the real narrative system.
  • Tests use GameExtension (headless libGDX) where engine classes are needed. Rendering and asset loading are mocked.

Run with ./gradlew test from source/. Reports: source/core/build/reports/tests/test/index.html.

Unit tests

NpcInteractionSequenceTest: ordering and locking (no libGDX)

Test Checks
dialogueOnlyNpcLocksUntilDialogueFinishes Lock → dialogue → unlock on finish
cutsceneOnlyNpcPlaysCutsceneWithoutDialogue Cutscene-only NPC works
cutsceneAfterDialogueKeepsControlsLockedBetweenSteps No unlock/relock flicker between steps
cutsceneBeforeDialogue BEFORE_DIALOGUE order
duringDialogueCueStartsCutsceneAndWaitsForBoth Cue starts cutscene; finishes only when both end
duringDialogueWithoutCueStillPlaysCutsceneAfterwards Missing cue doesn't skip the cutscene
cueIsIgnoredForOtherTimingsAndRepeatedCues Cue only affects DURING_DIALOGUE, only once
onlyLocksForStepsThatAskForIt Per-step lock flags
neverLocksWhenNothingAsksForIt Free-movement NPCs never lock
ignoresFinishEventsForOtherContent Other systems' finish events don't advance it
handlesContentThatFinishesSynchronously Missing content that reports "finished" immediately
cancelUnlocksWithoutFinishing Cancel releases the lock, doesn't complete
startIsIdempotent Calling start() twice has no effect

NpcInteractorComponentTest: player-side component

Test Checks
runsDialogueThenCutsceneAndRestoresControls Full flow through events with real PlayerActions
refusesASecondInteractionWhileBusy One interaction at a time
cueStartsDuringDialogueCutscene Cue event is forwarded
dyingCancelsAndUnlocksWithoutCompleting entityDied cancels cleanly
disposeReleasesLock No stuck lock on dispose
worksWithoutPlayerActions No crash on entities without PlayerActions
finishEventsWithNoActiveInteractionAreIgnored Stray events are harmless
markCompletedIsRemembered Completion API (for saving later)

NpcInteractableComponentTest: NPC-side rules

Test Checks
detectsRangeFromCentres In range at 1.4, out at 1.6 (range 1.5)
promptsWithNameAndVerb Prompt text
interactingStartsDialogue E starts the dialogue; NPC becomes BUSY
onceOnlyNpcCannotBeRepeated once + completedMessage
repeatableNpcCanBeTalkedToAgain Default is repeatable
waitsForRoomToBeCleared requiresRoomCleared + unavailableMessage
waitsForPrerequisiteNpc requiresCompleted
playerWithoutInteractorCannotInteract Safe when the player lacks the component
indicatorEventsFireOnlyOnChange No repeated show/hide events
interactingHidesIndicator Indicator hides on interact

FriendlyNpcManagerComponentTest: room-side spawning

Test Checks
roomWithoutNpcsLoadsNothing No asset loading for empty rooms
rejectsUnknownNpcIds Typo in rooms.json fails fast
loadsEachAtlasOnce Shared atlases loaded once
spawnsOnRoomCreatedAndFindsNearestInRange Spawning, registration, nearest NPC, prompt
showsIndicatorOnlyOnNearestAvailableNpc Only one indicator at a time
roomClearedConditionReadsTheEnemyManager Room-cleared condition tracks real enemy deaths
disposeUnloadsAssets Assets released on room change

RoomManagerNpcTest: key routing

Test Checks
npcInRangeConsumesTheKeyPress NPC takes priority over exits
unavailableNpcExplainsWhy Status message for unavailable NPC

InteractableNpcConfigsTest: configuration

Test Checks
shippedDefinitionsLoadAndValidate Real friendlyNpcs.json is valid
shippedDefinitionsCoverDialogueOnlyCutsceneOnlyAndBoth Shipped data exercises each kind
everyRoomSpawnNamesADefinedNpc rooms.json and friendlyNpcs.json agree
rejectsNpcWithNeitherDialogueNorCutscene Validation
rejectsDuplicateIds Validation
rejectsUnknownPrerequisite Validation
rejectsMissingSprite Validation
acceptsCutsceneOnlyNpcWithTexture Static texture path accepted

Additions to existing tests

Test Checks
InteractionPromptTest.shouldPromptForNpcWithVerbAndName NPC prompt text and defaults
InteractionPromptTest.shouldPreferNpcPromptOverItemAndExit Prompt priority
KeyboardPlayerInputComponentTest.shouldIgnoreEWhileNpcInteractionIsRunning E does nothing mid-interaction
KeyboardPlayerInputComponentTest.shouldNotPickUpItemWhenEStartsNpcInteraction One key press, one action

Manual test cases

Run from a fresh game. The NPCs are in the starting Dungeon Selection room.

# Steps Expected result
M1 Walk towards the Wandering Spirit Marker appears above it when in range; prompt reads "Press E — Talk to Wandering Spirit"; both disappear when walking away
M2 Press E next to the Spirit Dialogue opens; WASD, dash and attack do nothing
M3 Finish the dialogue Cutscene plays; controls still locked; controls return when it ends
M4 Press E on the Spirit again "The spirit has nothing more to say." No dialogue
M5 Before M2, press E on the Sealed Guardian Its unavailable message; nothing plays
M6 After M3, press E on the Guardian Cutscene only, no dialogue
M7 Talk to the Merchant twice Plays both times (repeatable)
M8 Attack and cast spells at an NPC No damage, no knockback, not targeted
M9 Stand where an NPC and a bookshelf exit are both in range, press E NPC interaction starts; room doesn't change
M10 Drop an item next to an NPC, press E NPC interaction starts; item isn't picked up
M11 Press E repeatedly during dialogue Interaction isn't restarted
M12 Leave the room and come back NPCs respawn; Spirit still shows its completed message
M13 Skip a dialogue or cutscene Controls return; sequence continues or ends normally

Edge cases and risks

Risk Mitigation
Narrative system never sends "finished", so controls are stuck Narrative system always sends "finished", including for skipped or missing content; contract documented above
Listener arity mismatch causes ClassCastException Arity fixed in the contract; tests listen with the documented signatures
Typo in rooms.json or friendlyNpcs.json Validated on load; config tests run against the real files
Invisible NPC from a wrong animation name Factory throws with the NPC id, atlas and animation
NPC spawned outside the map EntityManagerComponent rejects out-of-bounds spawns (logged)
Player dies mid-conversation Interaction cancelled and lock released

Table of Contents

Home

Test Plan

Team 2

Features

Components
Player
Items and Inventory
Enemies
Interactable NPCs
Cutscenes and Dialogue
Music
Bosses
Rooms
Weapons
Abilities & Spells
Game Screens and Areas
Dungeons

Game Engine

Getting Started

Entities and Components

Service Locator

Loading Resources

Logging

Unit Testing

Debug Terminal

Input Handling

UI

Animations

Audio

AI

Physics

Terrain

Concurrency & Threading

Settings

Troubleshooting

MacOS Setup Guide

Clone this wiki locally