Skip to content

TextBox Test Plan

Kinsey Dodd edited this page Sep 14, 2026 · 2 revisions

Test Plan: TextBox Feature

1. Overview

This document describes the test plan for the TextBox dialogue-box feature, covering:

Class Package Role
TextConfig com.csse3200.game.entities.configs Plain config POJO loaded from JSON; resolves colour/alignment strings into GDX types
TextBoxFactory com.csse3200.game.entities.factories Loads a TextConfig from disk and constructs a TextBoxComponent
TextBoxComponent com.csse3200.game.components Renders a typewriter-effect, paged dialogue box; handles TAB input to skip/advance/dismiss

Test implementation: JUnit 5, Mockito (mockito-junit-jupiter, mockito-inline), and the project's GameExtension headless-libGDX harness, per the "libGDX and Testing" course material.

2. Objectives

  • Verify TextConfig correctly parses and falls back on malformed/missing JSON-sourced values (colours, alignment).
  • Verify TextBoxFactory never throws regardless of config-loading outcome, and correctly delegates to FileLoader.
  • Verify TextBoxComponent's core interactive behaviour: page defaulting, the typewriter reveal timer, and the three-way TAB interaction (skip / advance page / dismiss).
  • Establish a safe, headless (no GPU/display) way to exercise UI components that depend on Gdx and ServiceLocator.

3. Scope

In scope: unit-level behaviour of the three classes above, using mocked collaborators (FileLoader, RenderService, Gdx.graphics, Gdx.input).

Out of scope:

  • Visual/pixel-level correctness of the rendered nine-patch scroll background (getBackgroundDrawable) — not asserted beyond "doesn't throw."
  • Real font rendering/metrics beyond what's needed for scene2d layout to run.
  • End-to-end/manual GUI testing (see ui.vision note in course material — libGDX can't be tested headless for true visual/functional GUI testing; out of scope for this automated suite).
  • Integration with the real flat-earth-ui.json skin asset pipeline beyond it being loadable (see Risks, §6).

4. Test Environment

  • Runner: JUnit 5 (Jupiter), with @ExtendWith(GameExtension.class) for any test that touches Gdx or constructs a UIComponent subclass.
  • Headless backend: GameExtension boots a HeadlessApplication and mocks Gdx.gl/Gdx.gl20 so no real GPU/display is required (safe for CI, e.g. GitHub Actions).
  • Mocking: Mockito for collaborators (FileLoader via mockito-inline static mocking, RenderService, Graphics, Input).
  • State isolation: ServiceLocator.clear() is called after each test (via GameExtension.afterEach and/or an explicit @AfterEach) to avoid state leaking between tests.
  • Known environment dependency: UIComponent.skin is a protected static final Skin loaded once from flat-earth/skin/flat-earth-ui.json via Gdx.files.internal(...) the first time the class is touched. Tests that construct a TextBoxComponent rely on that asset being resolvable from the test run's working directory; this can't be mocked away since it's a static field.

5. Test Case Summary

5.1 TextConfigTest

# Test Verifies
1 shouldHaveExpectedDefaultValues Default field values match spec (position, chars/sec, sizing, font path, alignment string, pages)
2 defaultColoursShouldResolveCorrectly Default colour strings resolve to Color.BLACK / TAN / BROWN
3 defaultAlignmentShouldResolveToCenter Default alignment resolves to Align.center
4 shouldParseColourWithColorPrefix "Color.RED" → Color.RED
5 shouldParseColourWithoutColorPrefix "BLUE" → Color.BLUE
6 shouldParseColourCaseInsensitively "color.green" → Color.GREEN
7 shouldFallBackToDefaultOnUnknownColourName Unknown name falls back to the fallback colour
8 shouldFallBackToDefaultOnNullColour null falls back to the fallback colour
9 shouldFallBackToDefaultOnBlankColour Blank/whitespace falls back to the fallback colour
10 shouldParseLeftAlignment / shouldParseRightAlignment "left"/"right" → Align.left/Align.right
11 shouldParseCentreSpellingAsCenter British spelling "centre" is accepted
12 shouldParseAlignmentCaseInsensitivelyWithWhitespace " RIGHT " → Align.right
13 shouldFallBackToCenterOnUnknownAlignment / OnNullAlignment / OnBlankAlignment Invalid/missing alignment defaults to center

5.2 TextBoxFactoryTest

# Test Verifies
1 shouldNotThrowWhenConfigFailsToLoad FileLoader.readClass returning null is handled without throwing (logged error path)
2 shouldReadConfigFromGivenFilePath FileLoader.readClass is called with (TextConfig.class, path) exactly once
3 shouldNotThrowWhenConfigLoadsSuccessfully A valid config leads to component construction/creation without an exception escaping the factory
4 shouldNotThrowWithNullFontPath A config with no font path falls through to the skin's default font without throwing

5.3 TextBoxComponentTest

# Test Verifies
1 shouldDefaultToSingleEmptyPageWhenPagesIsNull null pages → [""]
2 shouldDefaultToSingleEmptyPageWhenPagesIsEmpty Empty list → [""]
3 shouldKeepProvidedPagesWhenNonEmpty Non-empty pages are preserved as-is
4 shouldNotBuildActorsBeforeFirstDraw table stays uninitialised until the first draw() call
5 shouldGraduallyRevealCharactersOverTime Revealed character count increases proportionally to elapsed time × chars/sec, capping at full length
8 shouldNotShowTableWhenCurrentPageIsEmpty An empty page keeps the table hidden
9 firstTabPressShouldInstantlyRevealRestOfPage TAB while still typing reveals the full page immediately, without dismissing
10 tabOnLastFullyRevealedPageShouldDismissBox TAB on a fully-revealed, last page sets dismissed = true and hides the table
11 tabOnFullyRevealedNonLastPageShouldAdvanceToNextPage TAB on a fully-revealed, non-last page advances currentPageIndex and resets the typing state for the new page
12 drawShouldDoNothingOnceDismissed Further draw() calls after dismissal are a no-op (no exceptions, state unchanged)

6. Risks & Assumptions

Risk Mitigation / Notes
UIComponent.skin's static initializer fails if flat-earth/skin/flat-earth-ui.json isn't resolvable in the test run's working directory Not mockable (static final); relies on existing project test configuration. If it fails, the error surfaces as ExceptionInInitializerError on first use, not caught by TextBoxFactory's catch (Exception e).
Tests rely on reflection to read TextBoxComponent's private fields (pages, revealedChars, dismissed, currentPageIndex, lastSourceContent, table) Acceptable for a unit-test-only concern since it doesn't change production code; will need updating if those field names change.
RenderService/ResourceService method signatures assumed from UIComponent/ServiceLocator source (now confirmed: getStage() on RenderService) Confirmed against actual source as of this test suite's creation.
No true GUI/visual testing of the scroll background artwork Deliberately out of scope per course guidance (headless can't validate pixels); would need a tool like ui.vision on a real display for that.

7. Out-of-Scope / Follow-Up Suggestions

  • Add an integration test that runs TextBoxFactory.createTextBox against a real sample JSON file on the test classpath, rather than a fully mocked FileLoader.
  • Add a test for TextBoxComponent.dispose() verifying customFont.dispose() is invoked when a custom font was loaded.
  • If entity is ever set on the component, add a test covering the world-to-screen position calculation branch in draw().

Clone this wiki locally