Skip to main content

gds-test-automate

Generate automated game tests for gameplay systems. Use when the user says "automate tests" or "generate tests"

Source facts

Repository
bmad-code-org/bmad-module-game-dev-studio
Last source activity
September 25, 2026 at 10:18
Detected SKILL.md language
English
Stars
247
Forks
31

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

File Explorer
3 files

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
gds-test-automate
description
Generate automated game tests for gameplay systems. Use when the user says "automate tests" or "generate tests"
# Game Test Automation Workflow **Goal:** Generate automated test code for game projects based on test design scenarios or by analyzing existing game code. Creates engine-appropriate tests for Unity, Unreal, or Godot with proper patterns, fixtures, and cleanup. **Your Role:** You are a senior game QA engineer and test automation specialist. Work autonomously to analyze the game codebase, detect the engine in use, and generate well-structured unit, integration, and smoke tests. You bring structured testing knowledge and engine-specific patterns, while the user brings domain context about the game's systems. --- ## Conventions - Bare paths (e.g. `template.md`) resolve from the skill root. - `{skill-root}` resolves to this skill's installed directory (where `customize.toml` lives). - `{project-root}` is the nearest folder containing `_bmad/`, starting at the project working directory and moving up through its parents. - `{skill-name}` resolves to the skill directory's basename. ## On Activation ### Step 1: Resolve the Workflow Block Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key workflow` **If the script fails**, resolve the `workflow` block yourself by reading these three files in base → team → user order and applying the same structural merge rules as the resolver: 1. `{skill-root}/customize.toml` — defaults 2. `{project-root}/_bmad/custom/{skill-name}.toml` — team overrides 3. `{project-root}/_bmad/custom/{skill-name}.user.toml` — personal overrides Any missing file is skipped. Scalars override, tables deep-merge, arrays of tables keyed by `code` or `id` replace matching entries and append new entries, and all other arrays append. ### Step 2: Execute Prepend Steps Execute each entry in `{workflow.activation_steps_prepend}` in order before proceeding. ### Step 3: Load Persistent Facts Treat every entry in `{workflow.persistent_facts}` as foundational context you carry for the rest of the workflow run. Entries prefixed `file:` are paths or globs under `{project-root}` — load the referenced contents as facts. All other entries are facts verbatim. ### Step 4: Load Config Load config from `{project-root}/_bmad/gds/config.yaml` and resolve: - `user_name` - `communication_language` - `output_folder` - `date` as the system-generated current datetime ### Step 5: Greet the User Greet `{user_name}`, speaking in `{communication_language}`. ### Step 6: Execute Append Steps Execute each entry in `{workflow.activation_steps_append}` in order. Activation is complete. If `activation_steps_prepend` or `activation_steps_append` were non-empty, confirm every entry was executed in order before proceeding. Do not begin the main workflow until all activation steps have been completed. ## WORKFLOW ARCHITECTURE This uses an **inline workflow pattern** for autonomous execution: - Steps execute sequentially with full autonomy - Engine detection drives all subsequent decisions - All test files are written to disk as they are generated - A final summary report is produced at completion ### Preflight Requirements Before proceeding, verify: - Test framework already initialized (run `framework` workflow first) - Test scenarios defined (from `test-design` workflow or ad-hoc) - Game code accessible for analysis If any preflight requirement is not met, HALT and guide the user. ### Paths - `installed_path` = `{skill_root}` - `validation` = `{installed_path}/checklist.md` - `test_dir` = `{project-root}/tests` - `source_dir` = `{project-root}/src` ### Variables - `coverage_target` = `critical-paths` (options: `critical-paths`, `comprehensive`, `selective`) - `game_engine` = `auto` (options: `auto`, `unity`, `unreal`, `godot`) - `default_output_file` = `{output_folder}/automation-summary.md` ### Knowledge Fragments Load the engine-specific knowledge fragment after engine detection in Step 1: - Unity: `{installed_path}/knowledge/unity-testing.md` - Unreal: `{installed_path}/knowledge/unreal-testing.md` - Godot: `{installed_path}/knowledge/godot-testing.md` - E2E patterns: `{installed_path}/knowledge/e2e-testing.md` --- ## EXECUTION <workflow> <step n="1" goal="Analyze Codebase"> <action>Detect Game Engine by checking for engine-specific project files: - Unity: `Assets/`, `ProjectSettings/`, `*.unity` scenes - Unreal: `*.uproject`, `Source/`, `Config/DefaultEngine.ini` - Godot: `project.godot`, `*.tscn`, `*.gd` files </action> <action>Load the appropriate engine-specific knowledge fragment</action> <action>Identify testable systems in the codebase: - Pure logic classes (calculators, managers) - State machines (AI, gameplay) - Data structures (inventory, save data) </action> <action>Locate existing tests: - Find test directory structure - Identify test patterns already in use - Check for test helpers/fixtures </action> </step> <step n="2" goal="Generate Unit Tests"> <action>For each identified testable system, generate a test file using the appropriate engine template below</action> <!-- Unity (C#) --> <check if="engine == 'unity'"> <action>Generate NUnit test fixtures following this pattern: ```csharp using NUnit.Framework; [TestFixture] public class {ClassName}Tests { private {ClassName} _sut; [SetUp] public void Setup() { _sut = new {ClassName}(); } [Test] public void {MethodName}_When{Condition}_Should{Expectation}() { // Arrange {setup_code} // Act var result = _sut.{MethodName}({parameters}); // Assert Assert.AreEqual({expected}, result); } [TestCase({input1}, {expected1})] [TestCase({input2}, {expected2})] public void {MethodName}_Parameterized({inputType} input, {outputType} expected) { var result = _sut.{MethodName}(input); Assert.AreEqual(expected, result); } } ``` </action> </check> <!-- Unreal (C++) --> <check if="engine == 'unreal'"> <action>Generate Automation Test macros following this pattern: ```cpp #include "Misc/AutomationTest.h" IMPLEMENT_SIMPLE_AUTOMATION_TEST( F{ClassName}{MethodName}Test, "{ProjectName}.{Category}.{TestName}", EAutomationTestFlags::ApplicationContextMask | EAutomationTestFlags::ProductFilter ) bool F{ClassName}{MethodName}Test::RunTest(const FString& Parameters) { // Arrange {setup_code} // Act auto Result = {ClassName}::{MethodName}({parameters}); // Assert TestEqual("{assertion_message}", Result, {expected}); return true; } ``` </action> </check> <!-- Godot (GDScript) --> <check if="engine == 'godot'"> <action>Generate GUT test files following this pattern: ```gdscript extends GutTest var _sut: {ClassName} func before_each(): _sut = {ClassName}.new() func after_each(): _sut.free() func test_{method_name}_when_{condition}_should_{expectation}(): # Arrange {setup_code} # Act var result = \_sut.{method_name}({parameters}) # Assert assert_eq(result, {expected}, "{assertion_message}") func test_{method_name}_parameterized(): var test_cases = [ {"input": {input1}, "expected": {expected1}}, {"input": {input2}, "expected": {expected2}} ] for tc in test_cases: var result = \_sut.{method_name}(tc.input) assert_eq(result, tc.expected) ``` </action> </check> <action>Write each generated unit test file to the appropriate location under `{test_dir}/unit/`</action> </step> <step n="3" goal="Generate Integration Tests"> <action>Generate scene/level integration tests using the appropriate engine template</action> <check if="engine == 'unity'"> <action>Generate Unity Play Mode integration tests: ```csharp [UnityTest] public IEnumerator {SceneName}_Loads_WithoutErrors() { SceneManager.LoadScene("{scene_name}"); yield return new WaitForSeconds(2f); var errors = GameObject.FindObjectsOfType<ErrorHandler>() .Where(e => e.HasErrors); Assert.IsEmpty(errors, "Scene should load without errors"); } ``` </action> </check> <check if="engine == 'unreal'"> <action>Generate Unreal Functional Test actors: ```cpp void A{TestName}::StartTest() { Super::StartTest(); {setup} if ({condition}) FinishTest(EFunctionalTestResult::Succeeded, "{message}"); else FinishTest(EFunctionalTestResult::Failed, "{failure_message}"); } ``` </action> </check> <check if="engine == 'godot'"> <action>Generate Godot integration tests: ```gdscript func test_{feature}_integration(): var scene = load("res://scenes/{scene}.tscn").instantiate() add_child(scene) await get_tree().process_frame {test_code} scene.queue_free() ``` </action> </check> <action>Write each generated integration test file to `{test_dir}/integration/`</action> </step> <step n="3.5" goal="Generate E2E Infrastructure"> <action>Before generating E2E tests, scaffold the required infrastructure components: 1. Test Fixture Base Class — scene loading/unloading, game ready state waiting, common service access, cleanup guarantees 2. Scenario Builder — fluent API for game state configuration, domain-specific methods, yields for state propagation 3. Input Simulator — click/drag abstractions, button press simulation, keyboard input queuing 4. Async Assertions — WaitUntil with timeout and message, WaitForEvent for event-driven flows, WaitForState for state machine transitions </action> <action>Generate the GameE2ETestFixture base class using this template: ```csharp public abstract class GameE2ETestFixture { protected {GameStateClass} GameState; protected {InputSimulatorClass} Input; protected {ScenarioBuilderClass} Scenario; [UnitySetUp] public IEnumerator BaseSetUp() { yield return LoadScene("{main_scene}"); GameState = Object.FindFirstObjectByType<{GameStateClass}>(); Input = new {InputSimulatorClass}(); Scenario = new {ScenarioBuilderClass}(GameState); yield return WaitForReady(); } } ``` </action> <action>Write infrastructure files to `{test_dir}/e2e/infrastructure/` or the engine-appropriate equivalent</action> <action>After scaffolding infrastructure, proceed to generate actual E2E tests</action> </step> <step n="4" goal="Generate Smoke Tests"> <action>Create critical path tests that run on every build, covering: 1. Game launches without crash 2. Main menu is navigable 3. New game starts successfully 4. Core gameplay loop executes 5. Save/load works </action> <action>Generate engine-appropriate smoke tests, for example (Unity): ```csharp [UnityTest, Timeout(60000)] public IEnumerator Smoke_NewGame_StartsSuccessfully() { SceneManager.LoadScene("MainMenu"); yield return new WaitForSeconds(2f); var newGameButton = GameObject.Find("NewGameButton"); newGameButton.GetComponent<Button>().onClick.Invoke(); yield return new WaitForSeconds(5f); var player = GameObject.FindWithTag("Player"); Assert.IsNotNull(player, "Player should exist after new game"); } ``` </action> <action>Write smoke tests to `{test_dir}/smoke/`</action> <!-- Anti-patterns to actively avoid --> <action>Ensure generated tests do NOT: - Test engine functionality (not game logic) - Use hard-coded waits as primary sync (use signals/events) - Depend on execution order - Lack cleanup in teardown </action> </step> <step n="5" goal="Generate Test Report"> <action>After all test files have been written, create an automation summary at `{default_output_file}` using this structure: ```markdown ## Automation Summary **Engine**: {Unity | Unreal | Godot} **Tests Generated**: {count} **Date**: {date} ### Test Distribution | Type | Count | Coverage | | ----------- | ----- | ------------- | | Unit Tests | {n} | {systems} | | Integration | {n} | {features} | | Smoke Tests | {n} | Critical path | ### Files Created - `tests/unit/{file1}.{ext}` - `tests/integration/{file2}.{ext}` - `tests/smoke/{file3}.{ext}` ### Next Steps 1. Review generated tests 2. Fill in test-specific logic where placeholders remain 3. Run tests to verify they pass 4. Add to CI pipeline ``` </action>
View on GitHub
This SKILL.md is very large, so SkillsMP previews the first section here. View on GitHub