Boss AI Test Plan Sprint 3 - UQcsse3200/2026-studio-3 GitHub Wiki

Boss AI Test Plan Sprint 3

Scope: Boss phase system, weighted decisions, global pressure, Debuff cooldown and Enemy Memory response

Implementation and tests: commit 231f3a91

Integration: Feature-1 branch

Purpose

BossAI controls Vitium through an irreversible three-phase state machine, phase-specific weighted action tables, global battle pressure, action-history constraints, two Debuff actions and a shared Debuff cooldown.

The Boss also reads PlayerMemory. When the player played at least four cards during the previous turn, the Boss prioritises SILENCE, provided that the shared Debuff cooldown has expired.

This page records the automated tests for the Boss decision layer. It covers the EnemyIntent selected by BossAI and its internal decision state. It does not claim to test animation, intent-icon rendering, status-effect execution or full battle-scene integration.

Automated test coverage

BossAITest currently contains 24 JUnit tests.

Test class Tests What they check
BossAITest 24 Phase boundaries, irreversible transitions, attack and defence intents, pressure, armour constraints, action history, Debuff selection, shared cooldown and memory-driven SILENCE.

The tests inject deterministic implementations of Random:

Test random source Purpose
FixedRollRandom Selects a known position in the final weighted action table
SequenceRandom Produces a planned series of decisions for action-history tests

This avoids flaky tests while preserving the runtime weighted-random design.

Test groups

Group Tests Coverage
Phase state machine 4 Initial phase, 65% boundary, 30% boundary and irreversible progression
Basic actions and pressure 5 Attack, Phase One defence, Phase Two defence, high-armour constraint and pressure response
Internal action state 4 Previous move, consecutive attacks, attack-counter reset and null-context rejection
Debuff behaviour 6 Phase restrictions, SILENCE, DAMAGE_ON_CARD_PLAY, repeated-Debuff prevention, cooldown expiry and attack-counter reset
Player-memory behaviour 5 Four-card trigger, below-threshold behaviour, cooldown protection, post-cooldown reaction and shared cooldown

Acceptance-criteria traceability

# Required behaviour Automated evidence Result or gap
1 The Boss begins in PHASE_ONE. shouldStartInPhaseOne() Covered.
2 Boss health at or below 65% enters PHASE_TWO. shouldEnterPhaseTwoAtSixtyFivePercentHealth() Covered at the exact boundary.
3 Boss health at or below 30% enters ENRAGED. shouldEnterEnragedPhaseAtThirtyPercentHealth() Covered at the exact boundary.
4 Healing cannot move the Boss back to an earlier phase. shouldNotReturnToEarlierPhaseAfterHealing() Covered.
5 The Boss can create an attack intent using its current attack value. shouldProduceAttackIntent() Covered.
6 Defence becomes stronger in Phase Two. shouldProducePhaseOneDefendIntent() and shouldUseStrongerDefenceInPhaseTwo() compare values 4 and 6. Covered for Phase One and Phase Two. The Enraged defence value of 8 has no dedicated test.
7 The Boss does not defend when armour is already at the configured high-armour threshold. shouldAttackWhenArmourIsAlreadyHigh() Covered at armour 8.
8 Higher battle pressure makes the Boss more aggressive. shouldBecomeMoreAggressiveUnderHighPressure() uses the same roll for low- and high-pressure contexts and receives different intents. Covered behaviourally. Individual pressure-level boundaries are not directly tested.
9 The Boss records its previous move. shouldRecordPreviousMove() Covered.
10 Consecutive attacks are counted and reset by a non-attack action. shouldCountConsecutiveAttacks() and shouldResetConsecutiveAttacksAfterDefending() Covered.
11 A null AI context is rejected. shouldRejectNullContext() Covered.
12 Phase One cannot randomly select a Debuff without a memory trigger. shouldNotDebuffInPhaseOneWithoutMemoryTrigger() Covered.
13 Phase Two can select SILENCE with value 1 and duration 2. shouldSilenceThePlayerInPhaseTwo() Covered.
14 Enraged can select DAMAGE_ON_CARD_PLAY with damage 3 and duration 3. shouldDamageThePlayerOnCardPlayWhenEnraged() Covered.
15 The Boss cannot repeatedly select Debuffs while the cooldown is active. shouldNotDebuffTwiceInARow() Covered.
16 Debuffs become available again after three intervening decisions. shouldDebuffAgainOnceTheCooldownExpires() Covered.
17 Selecting a Debuff resets the consecutive-attack counter. shouldResetConsecutiveAttacksAfterDebuffing() Covered.
18 Four cards during the previous turn trigger prioritised SILENCE. shouldPrioritiseSilenceAfterFourCardsWerePlayed() checks type, effect, value, duration, recorded move and cooldown. Covered at the exact threshold.
19 Fewer than four cards do not trigger memory-driven SILENCE. shouldNotPrioritiseSilenceBelowCardThreshold() uses three cards and receives the normal attack result. Covered.
20 Player memory cannot bypass an active Debuff cooldown. shouldNotBypassDebuffCooldownForMemorySilence() Covered.
21 Memory-driven SILENCE can trigger again after cooldown expiry. shouldPrioritiseMemorySilenceAfterCooldownExpires() Covered.
22 SILENCE and DAMAGE_ON_CARD_PLAY share one cooldown. shouldShareCooldownBetweenCardPlayDamageAndMemorySilence() Covered.
23 Different Boss instances do not share phase, history or cooldown state. State fields are instance fields. Code structure verified; no dedicated instance-isolation test is currently present in BossAITest.
24 A null injected Random is rejected. Constructor uses Objects.requireNonNull. Code verified; no dedicated constructor test is currently present.

Decision-path coverage

EnemyAIContext
      |
      v
Update phase
      |
      v
Tick Debuff cooldown
      |
      v
Calculate pressure
      |
      v
Create phase weights
      |
      v
Apply pressure and constraints
      |
      v
Check PlayerMemory
      |
      +-- cardsPlayedLastTurn >= 4 and cooldown ready --> SILENCE
      |
      +-- otherwise --> deterministic weighted selection in tests
      |
      v
Record move and return EnemyIntent

The tests directly exercise both final branches:

  • Memory-prioritised SILENCE;
  • Normal weighted action selection.

How to run the tests

Use JDK 21 and run commands from the repository's source directory.

On Windows PowerShell:

.\gradlew.bat :core:test --tests "com.csse3200.game.components.enemy.EnemyAI.BossAITest"
.\gradlew.bat test
.\gradlew.bat spotlessCheck
.\gradlew.bat :core:jacocoTestReport

On macOS/Linux:

./gradlew :core:test --tests "com.csse3200.game.components.enemy.EnemyAI.BossAITest"
./gradlew test
./gradlew spotlessCheck
./gradlew :core:jacocoTestReport

The JaCoCo HTML report is generated at:

source/core/build/reports/jacoco/test/html/index.html

The Team 1 test policy targets at least 90% instruction coverage and 80% branch coverage. The generated report should be checked specifically for BossAI, rather than treating a passing test task alone as proof of coverage.

Recorded results and limits

The branch contains 24 focused BossAITest cases. This page does not attach a fresh Gradle or JaCoCo report for the latest Feature-1 head, so the commands above must be rerun after updating the branch.

The tests validate AI decision output and internal Boss state. They do not directly validate:

  • Application of SILENCE to the player;
  • Runtime damage from DAMAGE_ON_CARD_PLAY;
  • Intent icons;
  • Boss animations;
  • JSON enemy creation;
  • Full tutorial or battle-scene flow;
  • Statistical probability distribution over many random rolls.

Those responsibilities belong to integration, behaviour-component, UI and manual battle tests.

Useful follow-up regression tests are:

  • Enraged defence returns value 8;
  • Two BossAI instances keep independent state;
  • A null injected Random is rejected;
  • Exact LOW, MEDIUM, HIGH and CRITICAL pressure boundaries.