[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M71NHCF74EKPBA80WR3EBJ2F":3,"skill-same:01M71NHCF74EKPBA80WR3EBJ2F":74},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":22,"publishedAt":36,"linkOnly":37,"markdownContent":38,"markdownBody":39,"frontMatter":40,"refName":41,"commitSha":42,"skillDirectory":43,"forksCount":44,"repositoryHtmlUrl":45,"repositoryHomepageUrl":6,"ownerHtmlUrl":46,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":47,"install":48,"resources":61},"01M71NHCF74EKPBA80WR3EBJ2F","gds-test-automate",null,"Generate automated game tests for gameplay systems. Use when the user says \"automate tests\" or \"generate tests\"","developAgent\u002Fbmad-start","developAgent","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F264530239?v=4","01M71J8X6CY24V5ZZHFGETRMSW","01M71J8X739FS28DGQAAY7V4QR",1,"MIT","https:\u002F\u002Fgithub.com\u002FdevelopAgent\u002Fbmad-start\u002Fblob\u002Fmain\u002F.iflow\u002Fskills\u002Fgds-test-automate\u002FSKILL.md",[17],{"categoryNo":18,"categoryName":19,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000008","测试与质量","SCENARIO","使用场景",[23,24,25,26,27,28,29,30,31,32,33,34,35],"test","automate","gds test automate","generate","game","user","use","generate tests","gameplay","tests","systems","for","when","2026-11-10 10:56:23",false,"---\nname: gds-test-automate\ndescription: 'Generate automated game tests for gameplay systems. Use when the user says \"automate tests\" or \"generate tests\"'\n---\n\n# Game Test Automation Workflow\n\n**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.\n\n**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.\n\n---\n\n## Conventions\n\n- Bare paths (e.g. `template.md`) resolve from the skill root.\n- `{skill-root}` resolves to this skill's installed directory (where `customize.toml` lives).\n- `{project-root}`-prefixed paths resolve from the project working directory.\n- `{skill-name}` resolves to the skill directory's basename.\n\n## On Activation\n\n### Step 1: Resolve the Workflow Block\n\nRun: `python3 {project-root}\u002F_bmad\u002Fscripts\u002Fresolve_customization.py --skill {skill-root} --key workflow`\n\n**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:\n\n1. `{skill-root}\u002Fcustomize.toml` — defaults\n2. `{project-root}\u002F_bmad\u002Fcustom\u002F{skill-name}.toml` — team overrides\n3. `{project-root}\u002F_bmad\u002Fcustom\u002F{skill-name}.user.toml` — personal overrides\n\nAny 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.\n\n### Step 2: Execute Prepend Steps\n\nExecute each entry in `{workflow.activation_steps_prepend}` in order before proceeding.\n\n### Step 3: Load Persistent Facts\n\nTreat 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.\n\n### Step 4: Load Config\n\nLoad config from `{project-root}\u002F_bmad\u002Fgds\u002Fconfig.yaml` and resolve:\n\n- `user_name`\n- `communication_language`\n- `output_folder`\n- `date` as the system-generated current datetime\n\n### Step 5: Greet the User\n\nGreet `{user_name}`, speaking in `{communication_language}`.\n\n### Step 6: Execute Append Steps\n\nExecute each entry in `{workflow.activation_steps_append}` in order.\n\nActivation is complete. Begin the workflow below.\n\n## WORKFLOW ARCHITECTURE\n\nThis uses an **inline workflow pattern** for autonomous execution:\n\n- Steps execute sequentially with full autonomy\n- Engine detection drives all subsequent decisions\n- All test files are written to disk as they are generated\n- A final summary report is produced at completion\n\n### Preflight Requirements\n\nBefore proceeding, verify:\n\n- Test framework already initialized (run `framework` workflow first)\n- Test scenarios defined (from `test-design` workflow or ad-hoc)\n- Game code accessible for analysis\n\nIf any preflight requirement is not met, HALT and guide the user.\n\n\n### Paths\n\n- `installed_path` = `{skill_root}`\n- `validation` = `{installed_path}\u002Fchecklist.md`\n- `test_dir` = `{project-root}\u002Ftests`\n- `source_dir` = `{project-root}\u002Fsrc`\n\n### Variables\n\n- `coverage_target` = `critical-paths` (options: `critical-paths`, `comprehensive`, `selective`)\n- `game_engine` = `auto` (options: `auto`, `unity`, `unreal`, `godot`)\n- `default_output_file` = `{output_folder}\u002Fautomation-summary.md`\n\n### Knowledge Fragments\n\nLoad the engine-specific knowledge fragment after engine detection in Step 1:\n\n- Unity: `{installed_path}\u002Fknowledge\u002Funity-testing.md`\n- Unreal: `{installed_path}\u002Fknowledge\u002Funreal-testing.md`\n- Godot: `{installed_path}\u002Fknowledge\u002Fgodot-testing.md`\n- E2E patterns: `{installed_path}\u002Fknowledge\u002Fe2e-testing.md`\n\n---\n\n## EXECUTION\n\n\u003Cworkflow>\n\n\u003Cstep n=\"1\" goal=\"Analyze Codebase\">\n  \u003Caction>Detect Game Engine by checking for engine-specific project files:\n    - Unity: `Assets\u002F`, `ProjectSettings\u002F`, `*.unity` scenes\n    - Unreal: `*.uproject`, `Source\u002F`, `Config\u002FDefaultEngine.ini`\n    - Godot: `project.godot`, `*.tscn`, `*.gd` files\n  \u003C\u002Faction>\n  \u003Caction>Load the appropriate engine-specific knowledge fragment\u003C\u002Faction>\n  \u003Caction>Identify testable systems in the codebase:\n    - Pure logic classes (calculators, managers)\n    - State machines (AI, gameplay)\n    - Data structures (inventory, save data)\n  \u003C\u002Faction>\n  \u003Caction>Locate existing tests:\n    - Find test directory structure\n    - Identify test patterns already in use\n    - Check for test helpers\u002Ffixtures\n  \u003C\u002Faction>\n\u003C\u002Fstep>\n\n\u003Cstep n=\"2\" goal=\"Generate Unit Tests\">\n  \u003Caction>For each identified testable system, generate a test file using the appropriate engine template below\u003C\u002Faction>\n\n  \u003C!-- Unity (C#) -->\n  \u003Ccheck if=\"engine == 'unity'\">\n    \u003Caction>Generate NUnit test fixtures following this pattern:\n```csharp\nusing NUnit.Framework;\n\n[TestFixture]\npublic class {ClassName}Tests\n{\n    private {ClassName} _sut;\n\n    [SetUp]\n    public void Setup()\n    {\n        _sut = new {ClassName}();\n    }\n\n    [Test]\n    public void {MethodName}_When{Condition}_Should{Expectation}()\n    {\n        \u002F\u002F Arrange\n        {setup_code}\n        \u002F\u002F Act\n        var result = _sut.{MethodName}({parameters});\n        \u002F\u002F Assert\n        Assert.AreEqual({expected}, result);\n    }\n\n    [TestCase({input1}, {expected1})]\n    [TestCase({input2}, {expected2})]\n    public void {MethodName}_Parameterized({inputType} input, {outputType} expected)\n    {\n        var result = _sut.{MethodName}(input);\n        Assert.AreEqual(expected, result);\n    }\n}\n```\n    \u003C\u002Faction>\n  \u003C\u002Fcheck>\n\n  \u003C!-- Unreal (C++) -->\n  \u003Ccheck if=\"engine == 'unreal'\">\n    \u003Caction>Generate Automation Test macros following this pattern:\n```cpp\n#include \"Misc\u002FAutomationTest.h\"\n\nIMPLEMENT_SIMPLE_AUTOMATION_TEST(\n    F{ClassName}{MethodName}Test,\n    \"{ProjectName}.{Category}.{TestName}\",\n    EAutomationTestFlags::ApplicationContextMask |\n    EAutomationTestFlags::ProductFilter\n)\n\nbool F{ClassName}{MethodName}Test::RunTest(const FString& Parameters)\n{\n    \u002F\u002F Arrange\n    {setup_code}\n    \u002F\u002F Act\n    auto Result = {ClassName}::{MethodName}({parameters});\n    \u002F\u002F Assert\n    TestEqual(\"{assertion_message}\", Result, {expected});\n    return true;\n}\n```\n    \u003C\u002Faction>\n  \u003C\u002Fcheck>\n\n  \u003C!-- Godot (GDScript) -->\n  \u003Ccheck if=\"engine == 'godot'\">\n    \u003Caction>Generate GUT test files following this pattern:\n```gdscript\nextends GutTest\n\nvar _sut: {ClassName}\n\nfunc before_each():\n    _sut = {ClassName}.new()\n\nfunc after_each():\n    _sut.free()\n\nfunc test_{method_name}_when_{condition}_should_{expectation}():\n    # Arrange\n    {setup_code}\n    # Act\n    var result = \\_sut.{method_name}({parameters})\n    # Assert\n    assert_eq(result, {expected}, \"{assertion_message}\")\n\nfunc test_{method_name}_parameterized():\n    var test_cases = [\n        {\"input\": {input1}, \"expected\": {expected1}},\n        {\"input\": {input2}, \"expected\": {expected2}}\n    ]\n    for tc in test_cases:\n        var result = \\_sut.{method_name}(tc.input)\n        assert_eq(result, tc.expected)\n```\n    \u003C\u002Faction>\n  \u003C\u002Fcheck>\n\n  \u003Caction>Write each generated unit test file to the appropriate location under `{test_dir}\u002Funit\u002F`\u003C\u002Faction>\n\u003C\u002Fstep>\n\n\u003Cstep n=\"3\" goal=\"Generate Integration Tests\">\n  \u003Caction>Generate scene\u002Flevel integration tests using the appropriate engine template\u003C\u002Faction>\n\n  \u003Ccheck if=\"engine == 'unity'\">\n    \u003Caction>Generate Unity Play Mode integration tests:\n```csharp\n[UnityTest]\npublic IEnumerator {SceneName}_Loads_WithoutErrors()\n{\n    SceneManager.LoadScene(\"{scene_name}\");\n    yield return new WaitForSeconds(2f);\n    var errors = GameObject.FindObjectsOfType\u003CErrorHandler>()\n        .Where(e => e.HasErrors);\n    Assert.IsEmpty(errors, \"Scene should load without errors\");\n}\n```\n    \u003C\u002Faction>\n  \u003C\u002Fcheck>\n\n  \u003Ccheck if=\"engine == 'unreal'\">\n    \u003Caction>Generate Unreal Functional Test actors:\n```cpp\nvoid A{TestName}::StartTest()\n{\n    Super::StartTest();\n    {setup}\n    if ({condition})\n        FinishTest(EFunctionalTestResult::Succeeded, \"{message}\");\n    else\n        FinishTest(EFunctionalTestResult::Failed, \"{failure_message}\");\n}\n```\n    \u003C\u002Faction>\n  \u003C\u002Fcheck>\n\n  \u003Ccheck if=\"engine == 'godot'\">\n    \u003Caction>Generate Godot integration tests:\n```gdscript\nfunc test_{feature}_integration():\n    var scene = load(\"res:\u002F\u002Fscenes\u002F{scene}.tscn\").instantiate()\n    add_child(scene)\n    await get_tree().process_frame\n    {test_code}\n    scene.queue_free()\n```\n    \u003C\u002Faction>\n  \u003C\u002Fcheck>\n\n  \u003Caction>Write each generated integration test file to `{test_dir}\u002Fintegration\u002F`\u003C\u002Faction>\n\u003C\u002Fstep>\n\n\u003Cstep n=\"3.5\" goal=\"Generate E2E Infrastructure\">\n  \u003Caction>Before generating E2E tests, scaffold the required infrastructure components:\n    1. Test Fixture Base Class — scene loading\u002Funloading, game ready state waiting, common service access, cleanup guarantees\n    2. Scenario Builder — fluent API for game state configuration, domain-specific methods, yields for state propagation\n    3. Input Simulator — click\u002Fdrag abstractions, button press simulation, keyboard input queuing\n    4. Async Assertions — WaitUntil with timeout and message, WaitForEvent for event-driven flows, WaitForState for state machine transitions\n  \u003C\u002Faction>\n  \u003Caction>Generate the GameE2ETestFixture base class using this template:\n```csharp\npublic abstract class GameE2ETestFixture\n{\n    protected {GameStateClass} GameState;\n    protected {InputSimulatorClass} Input;\n    protected {ScenarioBuilderClass} Scenario;\n\n    [UnitySetUp]\n    public IEnumerator BaseSetUp()\n    {\n        yield return LoadScene(\"{main_scene}\");\n        GameState = Object.FindFirstObjectByType\u003C{GameStateClass}>();\n        Input = new {InputSimulatorClass}();\n        Scenario = new {ScenarioBuilderClass}(GameState);\n        yield return WaitForReady();\n    }\n}\n```\n  \u003C\u002Faction>\n  \u003Caction>Write infrastructure files to `{test_dir}\u002Fe2e\u002Finfrastructure\u002F` or the engine-appropriate equivalent\u003C\u002Faction>\n  \u003Caction>After scaffolding infrastructure, proceed to generate actual E2E tests\u003C\u002Faction>\n\u003C\u002Fstep>\n\n\u003Cstep n=\"4\" goal=\"Generate Smoke Tests\">\n  \u003Caction>Create critical path tests that run on every build, covering:\n    1. Game launches without crash\n    2. Main menu is navigable\n    3. New game starts successfully\n    4. Core gameplay loop executes\n    5. Save\u002Fload works\n  \u003C\u002Faction>\n  \u003Caction>Generate engine-appropriate smoke tests, for example (Unity):\n```csharp\n[UnityTest, Timeout(60000)]\npublic IEnumerator Smoke_NewGame_StartsSuccessfully()\n{\n    SceneManager.LoadScene(\"MainMenu\");\n    yield return new WaitForSeconds(2f);\n    var newGameButton = GameObject.Find(\"NewGameButton\");\n    newGameButton.GetComponent\u003CButton>().onClick.Invoke();\n    yield return new WaitForSeconds(5f);\n    var player = GameObject.FindWithTag(\"Player\");\n    Assert.IsNotNull(player, \"Player should exist after new game\");\n}\n```\n  \u003C\u002Faction>\n  \u003Caction>Write smoke tests to `{test_dir}\u002Fsmoke\u002F`\u003C\u002Faction>\n\n  \u003C!-- Anti-patterns to actively avoid -->\n  \u003Caction>Ensure generated tests do NOT:\n    - Test engine functionality (not game logic)\n    - Use hard-coded waits as primary sync (use signals\u002Fevents)\n    - Depend on execution order\n    - Lack cleanup in teardown\n  \u003C\u002Faction>\n\u003C\u002Fstep>\n\n\u003Cstep n=\"5\" goal=\"Generate Test Report\">\n  \u003Caction>After all test files have been written, create an automation summary at `{default_output_file}` using this structure:\n\n```markdown\n## Automation Summary\n\n**Engine**: {Unity | Unreal | Godot}\n**Tests Generated**: {count}\n**Date**: {date}\n\n### Test Distribution\n\n| Type        | Count | Coverage      |\n| ----------- | ----- | ------------- |\n| Unit Tests  | {n}   | {systems}     |\n| Integration | {n}   | {features}    |\n| Smoke Tests | {n}   | Critical path |\n\n### Files Created\n\n- `tests\u002Funit\u002F{file1}.{ext}`\n- `tests\u002Fintegration\u002F{file2}.{ext}`\n- `tests\u002Fsmoke\u002F{file3}.{ext}`\n\n### Next Steps\n\n1. Review generated tests\n2. Fill in test-specific logic where placeholders remain\n3. Run tests to verify they pass\n4. Add to CI pipeline\n```\n  \u003C\u002Faction>\n  \u003Caction>Load and apply `{validation}` checklist to verify all deliverables are complete\u003C\u002Faction>\n  \u003Caction>Present the automation summary to the user\u003C\u002Faction>\n\u003Caction>Run: `python3 {project-root}\u002F_bmad\u002Fscripts\u002Fresolve_customization.py --skill {skill-root} --key workflow.on_complete` — if the resolved value is non-empty, follow it as the final terminal instruction before exiting.\u003C\u002Faction>\n\u003C\u002Fstep>\n\n\u003C\u002Fworkflow>\n","# Game Test Automation Workflow\n\n**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.\n\n**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.\n\n---\n\n## Conventions\n\n- Bare paths (e.g. `template.md`) resolve from the skill root.\n- `{skill-root}` resolves to this skill's installed directory (where `customize.toml` lives).\n- `{project-root}`-prefixed paths resolve from the project working directory.\n- `{skill-name}` resolves to the skill directory's basename.\n\n## On Activation\n\n### Step 1: Resolve the Workflow Block\n\nRun: `python3 {project-root}\u002F_bmad\u002Fscripts\u002Fresolve_customization.py --skill {skill-root} --key workflow`\n\n**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:\n\n1. `{skill-root}\u002Fcustomize.toml` — defaults\n2. `{project-root}\u002F_bmad\u002Fcustom\u002F{skill-name}.toml` — team overrides\n3. `{project-root}\u002F_bmad\u002Fcustom\u002F{skill-name}.user.toml` — personal overrides\n\nAny 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.\n\n### Step 2: Execute Prepend Steps\n\nExecute each entry in `{workflow.activation_steps_prepend}` in order before proceeding.\n\n### Step 3: Load Persistent Facts\n\nTreat 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.\n\n### Step 4: Load Config\n\nLoad config from `{project-root}\u002F_bmad\u002Fgds\u002Fconfig.yaml` and resolve:\n\n- `user_name`\n- `communication_language`\n- `output_folder`\n- `date` as the system-generated current datetime\n\n### Step 5: Greet the User\n\nGreet `{user_name}`, speaking in `{communication_language}`.\n\n### Step 6: Execute Append Steps\n\nExecute each entry in `{workflow.activation_steps_append}` in order.\n\nActivation is complete. Begin the workflow below.\n\n## WORKFLOW ARCHITECTURE\n\nThis uses an **inline workflow pattern** for autonomous execution:\n\n- Steps execute sequentially with full autonomy\n- Engine detection drives all subsequent decisions\n- All test files are written to disk as they are generated\n- A final summary report is produced at completion\n\n### Preflight Requirements\n\nBefore proceeding, verify:\n\n- Test framework already initialized (run `framework` workflow first)\n- Test scenarios defined (from `test-design` workflow or ad-hoc)\n- Game code accessible for analysis\n\nIf any preflight requirement is not met, HALT and guide the user.\n\n\n### Paths\n\n- `installed_path` = `{skill_root}`\n- `validation` = `{installed_path}\u002Fchecklist.md`\n- `test_dir` = `{project-root}\u002Ftests`\n- `source_dir` = `{project-root}\u002Fsrc`\n\n### Variables\n\n- `coverage_target` = `critical-paths` (options: `critical-paths`, `comprehensive`, `selective`)\n- `game_engine` = `auto` (options: `auto`, `unity`, `unreal`, `godot`)\n- `default_output_file` = `{output_folder}\u002Fautomation-summary.md`\n\n### Knowledge Fragments\n\nLoad the engine-specific knowledge fragment after engine detection in Step 1:\n\n- Unity: `{installed_path}\u002Fknowledge\u002Funity-testing.md`\n- Unreal: `{installed_path}\u002Fknowledge\u002Funreal-testing.md`\n- Godot: `{installed_path}\u002Fknowledge\u002Fgodot-testing.md`\n- E2E patterns: `{installed_path}\u002Fknowledge\u002Fe2e-testing.md`\n\n---\n\n## EXECUTION\n\n\u003Cworkflow>\n\n\u003Cstep n=\"1\" goal=\"Analyze Codebase\">\n  \u003Caction>Detect Game Engine by checking for engine-specific project files:\n    - Unity: `Assets\u002F`, `ProjectSettings\u002F`, `*.unity` scenes\n    - Unreal: `*.uproject`, `Source\u002F`, `Config\u002FDefaultEngine.ini`\n    - Godot: `project.godot`, `*.tscn`, `*.gd` files\n  \u003C\u002Faction>\n  \u003Caction>Load the appropriate engine-specific knowledge fragment\u003C\u002Faction>\n  \u003Caction>Identify testable systems in the codebase:\n    - Pure logic classes (calculators, managers)\n    - State machines (AI, gameplay)\n    - Data structures (inventory, save data)\n  \u003C\u002Faction>\n  \u003Caction>Locate existing tests:\n    - Find test directory structure\n    - Identify test patterns already in use\n    - Check for test helpers\u002Ffixtures\n  \u003C\u002Faction>\n\u003C\u002Fstep>\n\n\u003Cstep n=\"2\" goal=\"Generate Unit Tests\">\n  \u003Caction>For each identified testable system, generate a test file using the appropriate engine template below\u003C\u002Faction>\n\n  \u003C!-- Unity (C#) -->\n  \u003Ccheck if=\"engine == 'unity'\">\n    \u003Caction>Generate NUnit test fixtures following this pattern:\n```csharp\nusing NUnit.Framework;\n\n[TestFixture]\npublic class {ClassName}Tests\n{\n    private {ClassName} _sut;\n\n    [SetUp]\n    public void Setup()\n    {\n        _sut = new {ClassName}();\n    }\n\n    [Test]\n    public void {MethodName}_When{Condition}_Should{Expectation}()\n    {\n        \u002F\u002F Arrange\n        {setup_code}\n        \u002F\u002F Act\n        var result = _sut.{MethodName}({parameters});\n        \u002F\u002F Assert\n        Assert.AreEqual({expected}, result);\n    }\n\n    [TestCase({input1}, {expected1})]\n    [TestCase({input2}, {expected2})]\n    public void {MethodName}_Parameterized({inputType} input, {outputType} expected)\n    {\n        var result = _sut.{MethodName}(input);\n        Assert.AreEqual(expected, result);\n    }\n}\n```\n    \u003C\u002Faction>\n  \u003C\u002Fcheck>\n\n  \u003C!-- Unreal (C++) -->\n  \u003Ccheck if=\"engine == 'unreal'\">\n    \u003Caction>Generate Automation Test macros following this pattern:\n```cpp\n#include \"Misc\u002FAutomationTest.h\"\n\nIMPLEMENT_SIMPLE_AUTOMATION_TEST(\n    F{ClassName}{MethodName}Test,\n    \"{ProjectName}.{Category}.{TestName}\",\n    EAutomationTestFlags::ApplicationContextMask |\n    EAutomationTestFlags::ProductFilter\n)\n\nbool F{ClassName}{MethodName}Test::RunTest(const FString& Parameters)\n{\n    \u002F\u002F Arrange\n    {setup_code}\n    \u002F\u002F Act\n    auto Result = {ClassName}::{MethodName}({parameters});\n    \u002F\u002F Assert\n    TestEqual(\"{assertion_message}\", Result, {expected});\n    return true;\n}\n```\n    \u003C\u002Faction>\n  \u003C\u002Fcheck>\n\n  \u003C!-- Godot (GDScript) -->\n  \u003Ccheck if=\"engine == 'godot'\">\n    \u003Caction>Generate GUT test files following this pattern:\n```gdscript\nextends GutTest\n\nvar _sut: {ClassName}\n\nfunc before_each():\n    _sut = {ClassName}.new()\n\nfunc after_each():\n    _sut.free()\n\nfunc test_{method_name}_when_{condition}_should_{expectation}():\n    # Arrange\n    {setup_code}\n    # Act\n    var result = \\_sut.{method_name}({parameters})\n    # Assert\n    assert_eq(result, {expected}, \"{assertion_message}\")\n\nfunc test_{method_name}_parameterized():\n    var test_cases = [\n        {\"input\": {input1}, \"expected\": {expected1}},\n        {\"input\": {input2}, \"expected\": {expected2}}\n    ]\n    for tc in test_cases:\n        var result = \\_sut.{method_name}(tc.input)\n        assert_eq(result, tc.expected)\n```\n    \u003C\u002Faction>\n  \u003C\u002Fcheck>\n\n  \u003Caction>Write each generated unit test file to the appropriate location under `{test_dir}\u002Funit\u002F`\u003C\u002Faction>\n\u003C\u002Fstep>\n\n\u003Cstep n=\"3\" goal=\"Generate Integration Tests\">\n  \u003Caction>Generate scene\u002Flevel integration tests using the appropriate engine template\u003C\u002Faction>\n\n  \u003Ccheck if=\"engine == 'unity'\">\n    \u003Caction>Generate Unity Play Mode integration tests:\n```csharp\n[UnityTest]\npublic IEnumerator {SceneName}_Loads_WithoutErrors()\n{\n    SceneManager.LoadScene(\"{scene_name}\");\n    yield return new WaitForSeconds(2f);\n    var errors = GameObject.FindObjectsOfType\u003CErrorHandler>()\n        .Where(e => e.HasErrors);\n    Assert.IsEmpty(errors, \"Scene should load without errors\");\n}\n```\n    \u003C\u002Faction>\n  \u003C\u002Fcheck>\n\n  \u003Ccheck if=\"engine == 'unreal'\">\n    \u003Caction>Generate Unreal Functional Test actors:\n```cpp\nvoid A{TestName}::StartTest()\n{\n    Super::StartTest();\n    {setup}\n    if ({condition})\n        FinishTest(EFunctionalTestResult::Succeeded, \"{message}\");\n    else\n        FinishTest(EFunctionalTestResult::Failed, \"{failure_message}\");\n}\n```\n    \u003C\u002Faction>\n  \u003C\u002Fcheck>\n\n  \u003Ccheck if=\"engine == 'godot'\">\n    \u003Caction>Generate Godot integration tests:\n```gdscript\nfunc test_{feature}_integration():\n    var scene = load(\"res:\u002F\u002Fscenes\u002F{scene}.tscn\").instantiate()\n    add_child(scene)\n    await get_tree().process_frame\n    {test_code}\n    scene.queue_free()\n```\n    \u003C\u002Faction>\n  \u003C\u002Fcheck>\n\n  \u003Caction>Write each generated integration test file to `{test_dir}\u002Fintegration\u002F`\u003C\u002Faction>\n\u003C\u002Fstep>\n\n\u003Cstep n=\"3.5\" goal=\"Generate E2E Infrastructure\">\n  \u003Caction>Before generating E2E tests, scaffold the required infrastructure components:\n    1. Test Fixture Base Class — scene loading\u002Funloading, game ready state waiting, common service access, cleanup guarantees\n    2. Scenario Builder — fluent API for game state configuration, domain-specific methods, yields for state propagation\n    3. Input Simulator — click\u002Fdrag abstractions, button press simulation, keyboard input queuing\n    4. Async Assertions — WaitUntil with timeout and message, WaitForEvent for event-driven flows, WaitForState for state machine transitions\n  \u003C\u002Faction>\n  \u003Caction>Generate the GameE2ETestFixture base class using this template:\n```csharp\npublic abstract class GameE2ETestFixture\n{\n    protected {GameStateClass} GameState;\n    protected {InputSimulatorClass} Input;\n    protected {ScenarioBuilderClass} Scenario;\n\n    [UnitySetUp]\n    public IEnumerator BaseSetUp()\n    {\n        yield return LoadScene(\"{main_scene}\");\n        GameState = Object.FindFirstObjectByType\u003C{GameStateClass}>();\n        Input = new {InputSimulatorClass}();\n        Scenario = new {ScenarioBuilderClass}(GameState);\n        yield return WaitForReady();\n    }\n}\n```\n  \u003C\u002Faction>\n  \u003Caction>Write infrastructure files to `{test_dir}\u002Fe2e\u002Finfrastructure\u002F` or the engine-appropriate equivalent\u003C\u002Faction>\n  \u003Caction>After scaffolding infrastructure, proceed to generate actual E2E tests\u003C\u002Faction>\n\u003C\u002Fstep>\n\n\u003Cstep n=\"4\" goal=\"Generate Smoke Tests\">\n  \u003Caction>Create critical path tests that run on every build, covering:\n    1. Game launches without crash\n    2. Main menu is navigable\n    3. New game starts successfully\n    4. Core gameplay loop executes\n    5. Save\u002Fload works\n  \u003C\u002Faction>\n  \u003Caction>Generate engine-appropriate smoke tests, for example (Unity):\n```csharp\n[UnityTest, Timeout(60000)]\npublic IEnumerator Smoke_NewGame_StartsSuccessfully()\n{\n    SceneManager.LoadScene(\"MainMenu\");\n    yield return new WaitForSeconds(2f);\n    var newGameButton = GameObject.Find(\"NewGameButton\");\n    newGameButton.GetComponent\u003CButton>().onClick.Invoke();\n    yield return new WaitForSeconds(5f);\n    var player = GameObject.FindWithTag(\"Player\");\n    Assert.IsNotNull(player, \"Player should exist after new game\");\n}\n```\n  \u003C\u002Faction>\n  \u003Caction>Write smoke tests to `{test_dir}\u002Fsmoke\u002F`\u003C\u002Faction>\n\n  \u003C!-- Anti-patterns to actively avoid -->\n  \u003Caction>Ensure generated tests do NOT:\n    - Test engine functionality (not game logic)\n    - Use hard-coded waits as primary sync (use signals\u002Fevents)\n    - Depend on execution order\n    - Lack cleanup in teardown\n  \u003C\u002Faction>\n\u003C\u002Fstep>\n\n\u003Cstep n=\"5\" goal=\"Generate Test Report\">\n  \u003Caction>After all test files have been written, create an automation summary at `{default_output_file}` using this structure:\n\n```markdown\n## Automation Summary\n\n**Engine**: {Unity | Unreal | Godot}\n**Tests Generated**: {count}\n**Date**: {date}\n\n### Test Distribution\n\n| Type        | Count | Coverage      |\n| ----------- | ----- | ------------- |\n| Unit Tests  | {n}   | {systems}     |\n| Integration | {n}   | {features}    |\n| Smoke Tests | {n}   | Critical path |\n\n### Files Created\n\n- `tests\u002Funit\u002F{file1}.{ext}`\n- `tests\u002Fintegration\u002F{file2}.{ext}`\n- `tests\u002Fsmoke\u002F{file3}.{ext}`\n\n### Next Steps\n\n1. Review generated tests\n2. Fill in test-specific logic where placeholders remain\n3. Run tests to verify they pass\n4. Add to CI pipeline\n```\n  \u003C\u002Faction>\n  \u003Caction>Load and apply `{validation}` checklist to verify all deliverables are complete\u003C\u002Faction>\n  \u003Caction>Present the automation summary to the user\u003C\u002Faction>\n\u003Caction>Run: `python3 {project-root}\u002F_bmad\u002Fscripts\u002Fresolve_customization.py --skill {skill-root} --key workflow.on_complete` — if the resolved value is non-empty, follow it as the final terminal instruction before exiting.\u003C\u002Faction>\n\u003C\u002Fstep>\n\n\u003C\u002Fworkflow>\n",{"name":5,"description":7},"main","1907bbe850fb749efa8b499b8da7ebb78a663519",".iflow\u002Fskills\u002Fgds-test-automate",0,"https:\u002F\u002Fgithub.com\u002FdevelopAgent\u002Fbmad-start","https:\u002F\u002Fgithub.com\u002FdevelopAgent","2026-07-19 05:19:22",{"source":8,"skillName":5,"commands":49,"prompt":59,"zipAvailable":60},[50,53,56],{"tool":51,"command":52},"npx","npx skills add developAgent\u002Fbmad-start --skill gds-test-automate",{"tool":54,"command":55},"bunx","bunx skills add developAgent\u002Fbmad-start --skill gds-test-automate",{"tool":57,"command":58},"pnpm","pnpm dlx skills add developAgent\u002Fbmad-start --skill gds-test-automate","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FdevelopAgent\u002Fbmad-start\u002Fblob\u002Fmain\u002F.iflow\u002Fskills\u002Fgds-test-automate\u002FSKILL.md",true,[62,68],{"path":63,"resourceType":64,"resourceTypeDesc":65,"sizeBytes":66,"sourceHtmlUrl":67},"checklist.md","REFERENCE","参考文档",1681,"https:\u002F\u002Fgithub.com\u002FdevelopAgent\u002Fbmad-start\u002Fblob\u002Fmain\u002F.iflow\u002Fskills\u002Fgds-test-automate\u002Fchecklist.md",{"path":69,"resourceType":70,"resourceTypeDesc":71,"sizeBytes":72,"sourceHtmlUrl":73},"customize.toml","OTHER","其他",1615,"https:\u002F\u002Fgithub.com\u002FdevelopAgent\u002Fbmad-start\u002Fblob\u002Fmain\u002F.iflow\u002Fskills\u002Fgds-test-automate\u002Fcustomize.toml",[75,96,126,144,157,182],{"skillNo":76,"name":77,"nameZh":6,"description":78,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":79,"categories":80,"keywords":86,"publishedAt":95},"01M71R3M9DJTTY0ARFQ6K04NMP","gds-correct-course","Manage significant changes during sprint execution. Use when the user says \"correct course\" or \"propose sprint change\"","https:\u002F\u002Fgithub.com\u002FdevelopAgent\u002Fbmad-start\u002Fblob\u002Fmain\u002F.rovodev\u002Fskills\u002Fgds-correct-course\u002FSKILL.md",[81],{"categoryNo":82,"categoryName":83,"taxonomyType":84,"taxonomyTypeDesc":85},"01JBSEEDCAT000000000000039","教师与教育","PROFESSION","适用职业",[87,88,89,28,90,91,35,29,92,93,94],"gds correct course","course","correct","changes","change","execution","manage","sprint","2026-11-10 13:02:02",{"skillNo":97,"name":98,"nameZh":6,"description":99,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":100,"categories":101,"keywords":108,"publishedAt":95},"01M71R3GENSFD1A1XVZTTQG1KF","gds-code-review","Review code changes adversarially using parallel review layers (Blind Hunter, Edge Case Hunter, Acceptance Auditor) with structured triage into actionable categories. Use when the user says \"run code review\" or \"review this code\"","https:\u002F\u002Fgithub.com\u002FdevelopAgent\u002Fbmad-start\u002Fblob\u002Fmain\u002F.rovodev\u002Fskills\u002Fgds-code-review\u002FSKILL.md",[102,105],{"categoryNo":103,"categoryName":104,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000007","代码审查",{"categoryNo":106,"categoryName":107,"taxonomyType":84,"taxonomyTypeDesc":85},"01JBSEEDCAT000000000000030","开发工程师",[109,110,111,112,113,90,114,115,116,117,118,119,120,35,121,29,122,123,124,125],"code review","code","review","gds code review","categories","triage","review code","run","parallel","case","with","run code","acceptance","edge","actionable","layers","hunter",{"skillNo":127,"name":128,"nameZh":6,"description":129,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":130,"categories":131,"keywords":132,"publishedAt":95},"01M71R3DD098MQRD6F8S4GG0AW","gds-check-implementation-readiness","Verify GDD, UX, Architecture, and Epics alignment before production. Use when the user says \"check readiness\" or \"implementation readiness\"","https:\u002F\u002Fgithub.com\u002FdevelopAgent\u002Fbmad-start\u002Fblob\u002Fmain\u002F.rovodev\u002Fskills\u002Fgds-check-implementation-readiness\u002FSKILL.md",[],[133,134,135,136,137,138,28,139,140,141,142,35,29,143],"check","readiness","Implementation Readiness","gds check implementation readiness","implementation","check readiness","Production","ux","verify","architecture","alignment",{"skillNo":145,"name":146,"nameZh":6,"description":147,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":148,"categories":149,"keywords":150,"publishedAt":95},"01M71R3ACAA1G0NVQ330JQNJPK","gds-brainstorm-game","Facilitate game brainstorming sessions with game-specific techniques. Use when the user says \"brainstorm game\" or \"game ideas\"","https:\u002F\u002Fgithub.com\u002FdevelopAgent\u002Fbmad-start\u002Fblob\u002Fmain\u002F.rovodev\u002Fskills\u002Fgds-brainstorm-game\u002FSKILL.md",[],[151,27,152,28,153,119,35,29,154,155,156],"gds brainstorm game","brainstorm","brainstorming","techniques","sessions","ideas",{"skillNo":158,"name":159,"nameZh":6,"description":160,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":161,"categories":162,"keywords":166,"publishedAt":95},"01M71R377MJ6WJTTFARGKH3HX7","gds-agent-tech-writer","Technical documentation specialist and knowledge curator for game projects. Use when the user asks to talk to Paige or requests the Technical Writer.","https:\u002F\u002Fgithub.com\u002FdevelopAgent\u002Fbmad-start\u002Fblob\u002Fmain\u002F.rovodev\u002Fskills\u002Fgds-agent-tech-writer\u002FSKILL.md",[163],{"categoryNo":164,"categoryName":165,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000023","Skill与智能体开发",[167,168,169,170,29,171,172,34,173,35,28,174,175,176,177,178,179,180,27,181],"gds agent tech writer","tech","writer","technical writer","technical","knowledge","projects","technical documentation","talk","specialist","documentation specialist","knowledge curator","requests","documentation","curator",{"skillNo":183,"name":184,"nameZh":6,"description":185,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":186,"categories":187,"keywords":189,"publishedAt":95},"01M71R34RGT2ZX3TSFA2CRT0NC","gds-agent-game-solo-dev","Elite indie game developer for rapid prototyping and solo quick-flow development. Use when the user asks to talk to Indie or requests the Game Solo Dev.","https:\u002F\u002Fgithub.com\u002FdevelopAgent\u002Fbmad-start\u002Fblob\u002Fmain\u002F.rovodev\u002Fskills\u002Fgds-agent-game-solo-dev\u002FSKILL.md",[188],{"categoryNo":164,"categoryName":165,"taxonomyType":20,"taxonomyTypeDesc":21},[190,27,191,192,193,194,28,175,179,195,196,35,29,197,34,198,199],"solo","gds agent game solo dev","dev","flow","developer","RAPID","game developer","prototyping","development","quick"]