@@ -17,8 +17,8 @@
tests/
unit/ # 单元测试(公式/状态机/纯逻辑,隔离断言)——extends SceneTree + quit(code)
integration/ # 集成测试(跨系统闭环——与 unit/ 同一入口同一协议,见下「测试层级」节)
smoke_boot.tscn/.gd # 冒烟测试——极小启动场景(真实开机路径存活检查,闸 00 )
system_test.gd # 系统测试宿主薄壳(SceneTree+构造注入;断言迁移批后承接 smoke_all.gd,闸 01 )
smoke_boot.tscn/.gd # 冒烟测试——极小启动场景(真实开机路径存活检查)
system_test.gd # 系统测试宿主薄壳(SceneTree+构造注入;断言迁移批后承接 smoke_all.gd)
smoke/ # critical-paths.md——人工 gate 清单(/smoke-check 读取)
evidence/ # 截图与人工签核记录
run_all.gd # 单元与集成测试统一入口(套件 manifest 协议,D2 AC-2b)
@@ -29,11 +29,11 @@ tests/
| 层 | 判什么 | 承载 | 入闸方式 |
|---|---|---|---|
| **冒烟测试 ** | 这版活着吗——能否启动、能否加载表、能否进主屏。零逻辑判定 | `tests/smoke_boot.tscn/.gd` (以项目运行目标拉起=真实开机路径) | `run_smoke.py` (闸 00 ) |
| **单元测试 ** | 领域类的原子行为对不对(公式/状态机/纯逻辑)——从对外方法进、断言钉对外可观测面(写法判据见 test-conventions §8.2) | `tests/unit/` | `run_all.gd` manifest(闸 02 ) |
| **冒烟测试 ** | 这版活着吗——能否启动、能否加载表、能否进主屏。零逻辑判定 | `tests/smoke_boot.tscn/.gd` (以项目运行目标拉起=真实开机路径) | `run_smoke.py` ( 冒烟测试 闸) |
| **单元测试 ** | 领域类的原子行为对不对(公式/状态机/纯逻辑)——从对外方法进、断言钉对外可观测面(写法判据见 test-conventions §8.2) | `tests/unit/` | `run_all.gd` manifest( 单元与集成测试 闸) |
| **集成测试 ** | 跨系统的闭环对不对 | `tests/integration/` | 同上(与单元测试同一入口、同一协议) |
| **系统测试 ** | 启动真实工程走真实玩法路径 | 过渡期 `game/probe/smoke_all.gd` (断言迁移批后=`tests/system_test.gd` ) | `run_system_test.py` (闸 01 ) |
| **UI 探针+渲染 golden ** | 跑起来之后 UI 与场景切换对不对;画面基线 | `game/probe/*.tscn` 探针 | `probe_gate.sh` (闸 03 )、`render_gate.sh` (闸 05 ) |
| **系统测试 ** | 启动真实工程走真实玩法路径 | 过渡期 `game/probe/smoke_all.gd` (断言迁移批后=`tests/system_test.gd` ) | `run_system_test.py` ( 系统测试 闸) |
| **UI 探针+渲染 golden ** | 跑起来之后 UI 与场景切换对不对;画面基线 | `game/probe/*.tscn` 探针 | `probe_gate.sh` ( 场景探针 闸)、`render_gate.sh` ( 渲染 闸) |
> **integration/ 已建承载**。
> 首个集成用例 = `save_rng_roundtrip_test.gd`(存档⇄RNG 快照往返)。章程登记的四类集成用例里,
@@ -70,13 +70,13 @@ tests/
| 能力 | 系统 | 真实入口 | 代表用例(文件:函数) |
|---|---|---|---|
| 冒险生命周期:开局受理/三关序列/败北线 | 冒险结构 | `AdventureRunner.start_adventure()` / `continue_to_next_level()` | `adventure_feats_test.gd:_smoke_adventure_api` ; `adventure_feats_test.gd:_smoke_adventure` |
| 冒险生命周期:开局受理/三关序列/败北线 | 冒险结构 | `AdventureRunner.start_adventure()` / `continue_to_next_level()` | `adventure_feats_test.gd:_smoke_adventure_api` ; `adventure_feats_test.gd:_smoke_adventure` ; `hero_ledger_test.gd:_init` |
| 专长(奇物)授予与凭证保底 | 奇物 | `AdventureRunner.present_node_curio()` / `feats_held()` × 效果引擎兑付 | `adventure_feats_test.gd:_smoke_feats` ; `feat_vouchers_test.gd:_init` |
| 节点图生成合法性与同种子复现 | 关卡节点图生成 | `NodeMapGenerator.generate()` / `validate_output()` | `node_map_generator_test.gd:_test_output_ok` ; `node_map_generator_test.gd:_test_reproducible` ; `node_map_generator_test.gd:_test_exit_structure` |
| 节点图生长递增与无解 fail-fast | 关卡节点图生成 | `NodeMapGenerator.generate()` / `is_fatal()` | `node_map_growth_test.gd:_test_growth` ; `node_map_growth_test.gd:_test_fatal_subprocess` |
| 节点图参数读表与域单点(三参数驱动产物/生成器侧可行性保留) | 关卡节点图生成 | `NodeMapGenerator.generate()` / `LevelGenParams.validate()` | `node_map_generator_test.gd:_test_gen_params_table_driven` ; `table_structure_guard_test.gd:_test_level_gen_new_fields` |
| 节点图参数读表与域单点(三参数驱动产物/生成器侧可行性保留) | 关卡节点图生成 | `NodeMapGenerator.generate()` / `LevelGenParams.validate()` | `node_map_generator_test.gd:_test_gen_params_table_driven` ; `table_structure_guard_test.gd:_test_level_gen_new_fields` ; `level_gen_params_test.gd:_init` ; `encapsulation_p2_sweep_test.gd:_init` |
| 起关/选路/断点重生成同图(集成) | 关卡节点地图×关卡节点图生成×冒险结构 | `LevelRunner.start_level()` / `start_level_external()` / `pick_next_node()` ; `AdventureRunner.resume_adventure()` | `node_map_determinism_test.gd:_smoke_generated_map_determinism` |
| 信息迷雾类型可见性 | 关卡节点地图 | `LevelRunner.type_visible_ids()` | `level_map_type_vis_test.gd:_test_layer_distance` ; `level_map_type_vis_test.gd:_test_boss_exempt` ; `level_map_type_vis_test.gd:_test_resume_rebuild` |
| 信息迷雾类型可见性 | 关卡节点地图 | `LevelRunner.type_visible_ids()` | `level_map_type_vis_test.gd:_test_layer_distance` ; `level_map_type_vis_test.gd:_test_boss_exempt` ; `level_map_type_vis_test.gd:_test_resume_rebuild` ; `level_map_info_fog_test.gd:_initialize` |
| 关卡表消费侧校验与关卡推进 | 关卡节点地图×数据配置 | `LevelTable.validate_graph()` ; `LevelRunner.start_level()` | `level_table_validate_test.gd:_test_positive` ; `level_table_validate_test.gd:_test_negative` ; `level_shop_economy_test.gd:_smoke_level` |
**旅程段三:战斗结算 **
@@ -86,8 +86,8 @@ tests/
| 伤害公式与掷点乘区 | 战斗结算 | `DamageMath.pool_damage()` / `roll_discount_percent()` / `rolled_component()` | `damage_math_test.gd:_test_pool_damage` ; `damage_math_test.gd:_test_roll_discount_percent` ; `roll_multiplier_test.gd:_smoke_armor_roll` |
| 伤害单据编排与回放 | 战斗结算 | `DamageController.submit()` / `open_ticket()` / `flush()` | `damage_controller_test.gd:_run_recipe_sequence` ; `damage_controller_test.gd:_test_five_recipes_and_replay` |
| 效果发射端口单点 | 战斗结算 | `BattleOrchestrator.begin_battle()` (真实装配链端口接线+合成行闭面守卫经 `DamageController.flush_submit()` 承伤路径) | `effect_port_test.gd:_smoke_effect_port_wiring` ; `effect_port_test.gd:_test_business_classes_engine_free` ; `effect_port_test.gd:_test_biz_fact_face_closed` |
| 轮内流与结算五段全序 | 战斗结算 | `BattleOrchestrator.begin_battle()` | `round_flow_skill_pool_test.gd:_smoke_full_battle` ; `round_flow_skill_pool_test.gd:_smoke_settlement_segments` |
| 技能池数据面与回放独立 | 敌人系统 | `BattleOrchestrator.begin_battle()` (技能池抽号/校验) | `round_flow_skill_pool_test.gd:_smoke_skill_pool_data` ; `round_flow_skill_pool_test.gd:_smoke_skill_pool_replay_independence` |
| 轮内流与结算五段全序 | 战斗结算 | `BattleOrchestrator.begin_battle()` | `round_flow_skill_pool_test.gd:_smoke_full_battle` ; `round_flow_skill_pool_test.gd:_smoke_settlement_segments` ; `settle_segments_test.gd:_init` ; `settlement_wiring_snapshot_test.gd:_init` ; `encapsulation_sweep_test.gd:_init` |
| 技能池数据面与回放独立 | 敌人系统 | `BattleOrchestrator.begin_battle()` (技能池抽号/校验) | `round_flow_skill_pool_test.gd:_smoke_skill_pool_data` ; `round_flow_skill_pool_test.gd:_smoke_skill_pool_replay_independence` ; `trigger_cond_test.gd:_init` ; `pool_case_d_test.gd:_init` |
| Boss 半血解锁技门控 | 敌人系统 | `BattleOrchestrator.begin_battle()` ( Boss 行) | `skill_unlock_test.gd:_test_gate_predicate` ; `skill_unlock_test.gd:_test_latch_irreversible` |
| 封印与极性路由/不可逆 | 地图战斗资源×战斗结算 | 效果引擎 × `BattleOrchestrator.begin_battle()` | `seal_polarity_test.gd:_smoke_seal_ap_exhausted` ; `seal_polarity_test.gd:_smoke_seal_irreversible_quadrants` ; `seal_polarity_test.gd:_smoke_polarity_routing` |
| 变异布置门控 | 地形变异 | `BattleOrchestrator.begin_battle()` (变异布置段) | `variant_placement_test.gd:_smoke_variant_placement` ; `variant_placement_test.gd:_smoke_global_variant` ; `variant_placement_test.gd:_test_pack_min_from_table` |
@@ -103,7 +103,7 @@ tests/
| 元进度入账与锻造两轴 | 元进度×锻造工坊 | `MetaStateStore.apply_adventure_summary()` / `MetaStateStore.spend_keystone()` / `MetaStateStore.set_forge_route_level()` | `meta_progression_forge_test.gd:_meta_pricing_and_buy` ; `meta_progression_forge_test.gd:_smoke_forge_axes` |
| 锻造定价与购买闭环(全路线价格梯/多级购买扣款/拒购零副作用) | 锻造工坊 | `ForgeTable.level_price()` / `MetaProgression.forge_buy_level()` | `forge_table_test.gd:_test_price_ladder` ; `meta_progression_forge_test.gd:_meta_pricing_and_buy` ; `meta_progression_forge_test.gd:_test_forge_buy_reject` |
| 锻造与相邻通道隔离(祝福件购买锻造零变化/默认轴与钥匙解耦/甲型切换双轴可感) | 锻造工坊×元进度 | `MetaProgression.forge_select()` / `hero_type_axes()` /商店购买口 | `meta_progression_forge_test.gd:_test_blessing_no_forge_leak` ; `meta_progression_forge_test.gd:_test_default_axes_pre_key` ; `meta_progression_forge_test.gd:_test_armor_switch_dual_axes` |
| 天赋树购买与六键合成 | 天赋树 | `MetaProgression.tree_buy()` / `MetaStateStore.tree_state()` / `MetaStateStore.set_tree_level()` | `meta_progression_forge_test.gd:_smoke_tree` ; `meta_progression_forge_test.gd:_smoke_tree_rules` ; `tree_rules_v11_test.gd:_init` |
| 天赋树购买与六键合成 | 天赋树 | `MetaProgression.tree_buy()` / `MetaStateStore.tree_state()` / `MetaStateStore.set_tree_level()` | `meta_progression_forge_test.gd:_smoke_tree` ; `meta_progression_forge_test.gd:_smoke_tree_rules` ; `tree_rules_v11_test.gd:_init` ; `tree_requires_level_test.gd:_init` |
| 规则键参数读表(六键参数字典校验与激活侧透传) | 天赋树 | `MetaTreeTable.validate()` / `EffectEngine.rebuild()` / `MetaProgression.tree_rules()` | `tree_rules_v11_test.gd:_test_rule_key_params` |
| 秘宝结构冻结与 12 件效果 | 秘宝 | `TreasureItems.add_item()` / `query_inventory()` / `validate_use()` | `treasure_items_test.gd:_init` ; `treasure_effects_test.gd:_init` |
@@ -124,7 +124,7 @@ tests/
| 停手转存储备与轮内刷新(上限/AP 不重置/刷新图零清图奖励) | 行动经济 | `BattleOrchestrator.player_request_refresh()` / `MinesweeperRules.settle_batch()` | `round_flow_skill_pool_test.gd:_smoke_active_refresh` ; `seal_polarity_test.gd:_smoke_refresh_provenance_guard` ; `refresh_feats_test.gd:test_no_feats_baseline` |
| 换图系刷新链路与效果词表接线 | 行动经济×战斗结算×奇物 | `MinesweeperRules.settle_batch()` / `BattleOrchestrator.player_request_refresh()` | `effect_words_t1_test.gd:_init` ; `forge_table_test.gd:_test_effect_kinds_closed` ; `refresh_feats_test.gd:test_board_refresh_fact_only_on_success` |
| 换图基座:挖格产 RAP 与刷新折扣 | 行动经济×奇物 | `MinesweeperRules.settle_batch()` / `BattleOrchestrator.player_request_refresh()` | `refresh_feats_test.gd:test_reserve_on_accepted_dig` ; `refresh_feats_test.gd:test_refresh_discount_gate_and_charge` ; `refresh_feats_test.gd:test_double_base_stack` |
| 换图输出:刷新群伤与蓄力攻击 | 战斗结算×奇物 | `BattleOrchestrator.player_request_refresh()` →轮末 `MinesweeperRules.settle_batch(stop)` | `refresh_feats_test.gd:test_blast_defers_to_combat_segment` ; `refresh_feats_test.gd:test_charge_layers_consumed_same_round` |
| 换图输出:刷新群伤与蓄力攻击 | 战斗结算×奇物 | `BattleOrchestrator.player_request_refresh()` →轮末 `MinesweeperRules.settle_batch(stop)` | `refresh_feats_test.gd:test_blast_defers_to_combat_segment` ; `refresh_feats_test.gd:test_charge_layers_consumed_same_round` ; `run_time_fatal_test.gd:_init` |
| 换图生存:全局固定减伤与轮末恢复 | 战斗结算×奇物 | `BattleOrchestrator.player_request_refresh()` →敌方攻击/危险格/错误封印/地形真实受伤入口 | `refresh_feats_test.gd:test_all_hero_damage_paths_emit_once` ; `refresh_feats_test.gd:test_stone_mitigation_all_damage` ; `refresh_feats_test.gd:test_rest_rotation_cap_and_clear` |
| 换图资源:刷新固定 GP 收益 | 战斗结算×奇物 | `BattleOrchestrator.player_request_refresh()` | `refresh_feats_test.gd:test_mine_profit_gp` |
| 下轮行动点修正排队与兑现 | 行动经济 | `ActionEconomy.pending_ap_delta()` (排队经 `ActionEconomy.queue_ap_delta()` ,写入方为效果引擎) | `seal_polarity_test.gd:_smoke_negative_dictionary` ; `feat_vouchers_test.gd:_init` |
@@ -155,8 +155,8 @@ tests/
| 战斗叙述与终局文案(数值带入/胜负互异) | HUD框架 | `BattleNarrator.battle_end_text()` / `BattleNarrator.boss_name()` | `battle_narrator_test.gd:_test_numeric_lines_carry_values` ; `battle_narrator_test.gd:_test_end_text_differs_by_result` ; `battle_narrator_test.gd:_test_boss_name_uses_boss_rowset` |
| 玩家面文案与危险格格面字形 | HUD框架 | `BoardView.rebuild()` / `StatusSlotRow.set_effects()` | `player_copy_sweep_test.gd:_sweep_board_glyph` ; `player_copy_sweep_test.gd:_sweep_legend` ; `player_copy_sweep_test.gd:_sweep_hero_panel` |
| 营地场景图十层铺底与门洞留空呈现 | 营地场景视图 | 进入存档→选档→进档→营地场景屏(`CampSceneView.setup_layers()` 驱动);单元测试载入 `camp_scene_layout.tres` | `shot_probe.gd:_ready` ( camp 截图段);`camp_scene_layout_test.gd:_test_layout_hotspot_geometry` |
| 营地七物件命中区点选与分界面可达 | 营地场景视图 | 七物件命中区 → `CampSceneView._gui_input()` (命中发 `object_pressed` 信号) → 组合根开界面 | `ui_click_probe.gd:_ready` (七物件合成点击段) |
| 营地大门两分支确认与断点续玩接线 | 营地交互流 | 大门命中区 → ConfirmDialog(三出口)→ `main._on_confirm_accepted()` (新冒险确认)/`main._resume_from_menu()` (断点续玩) | `ui_click_probe.gd:_ready` (大门两分支段/断点确认段 :500-528 ) |
| 营地七物件命中区点选与分界面可达 | 营地场景视图 | 七物件命中区 → `CampSceneView._gui_input()` (命中发 `object_pressed` 信号) → 组合根开界面;**现役承载=emit 信号直发,标「接线验证」——真输入承载待建(残险登记,2026-11-05 真实入口口径收窄)** | `ui_click_probe.gd:_ready` (七物件合成点击段) |
| 营地大门两分支确认与断点续玩接线 | 营地交互流 | 大门命中区 → 合成鼠标事件经 `push_input` 真点( `ProbeUiUtil.push_click_at` )→ ConfirmDialog 真钮 (三出口)→ `main._on_confirm_accepted()` (新冒险确认)/`main._resume_from_menu()` (断点续玩) | `ui_click_probe.gd:_ready` (大门两分支段/断点确认段——真输入 push_click 驱动,2026-11-05 真输入化 ) |
| 四柜台拆解后五界面入口改挂与写口零回归 | 营地五界面 | 五界面意图信号 → `CampShopPresenter` → `MetaProgression.tree_buy()` 写口 | `forge_workbench_test.gd:_run` (承载类同迁断言十二项);`ui_click_probe.gd:_ready` (写口链段) |
| 营地篝火回主菜单与笔记本改挂动线 | 营地交互流 | 笔记本命中区 → `CareerOverlay.open()` ;篝火命中区 → ConfirmDialog 二次确认 → 主菜单 | `ui_struct_probe.gd:_ready` ( career 段);`screen_flow_probe.gd:_ready` (篝火/开合段) |
| 营地图鉴占位挂起态与反参照结构纪律 | 营地场景视图 | 布告板命中区 → `CampSceneView._gui_input()` ( object_pressed 信号) → 图鉴占位视图;营地根态场景树审计 | `ui_struct_probe.gd:_ready` (占位禁词/禁行段);`ui_struct_probe.gd:_ready` (结构禁词段) |
@@ -174,13 +174,13 @@ tests/
| 进度坐标查行:精确命中/向上取整/封顶/警告去重 | 数据配置 | `BoardGenTable.resolve_row()` / `ConfigDbResolver.resolve_enemy_rowset()` | `config_db_test.gd:_test_progress_resolution` ; `config_db_resolver_test.gd:_test_band_hit` ; `config_db_resolver_test.gd:_test_top_band_clamp` |
| 行集寻址、行序保序与难度乘数 clamp | 数据配置×难度曲线与Boss | `ConfigDbResolver.resolve_enemy_rowset()` / `ConfigDbResolver.resolve_difficulty_modifiers()` | `config_db_resolver_test.gd:_test_rowset_order_preserved` ; `config_db_resolver_test.gd:_test_row_kind_routing` ; `config_db_resolver_test.gd:_test_difficulty_clamp` |
| 运行期越域致命与进程非 0 退出 | 数据配置 | `BoardGenTable.resolve_row()` / `ConfigDbResolver.resolve_enemy_rowset()` | `config_db_fatal_oob_test.gd:_trigger_oob` ; `config_db_resolver_test.gd:_test_request_oob` |
| 加载期违规表拒绝:跨表悬空/计数器前缀/真视窄域/效果类型出域 | 数据配置×秘宝×奇物 | `ConfigDB.load_tables()` | `reward_dangling_treasure_test.gd:_init` ; `counter_prefix_fatal_test.gd:_assert_rejected` ; `treasure_target_violation_test.gd:_init` ; `effect_kind_retired_test.gd:_assert_rejected` |
| 加载期违规表拒绝:跨表悬空/计数器前缀/真视窄域/效果类型出域 | 数据配置×秘宝×奇物 | `ConfigDB.load_tables()` | `reward_dangling_treasure_test.gd:_init` ; `counter_prefix_fatal_test.gd:_assert_rejected` ; `treasure_target_violation_test.gd:_init` ; `effect_kind_retired_test.gd:_assert_rejected` ; `extended_row_violation_test.gd:_init` |
| 表结构守卫:域校验/行序键/跨字段互锁/配额锚 | 数据配置×敌人系统×地形变异×冒险结构 | `EnemyTable.validate()` / `VariationTable.variant_pool()` / `AdventureTable.validate()` | `table_structure_guard_test.gd:_smoke_enemy_bands` ; `table_structure_guard_test.gd:_smoke_variation_framework` ; `table_structure_guard_test.gd:_smoke_adventure_table` ; `table_structure_guard_test.gd:_test_feat_cap_required` |
| 变异表头域校验(地形变异) | 地形变异 | `VariationTable.validate()` | `table_structure_guard_test.gd:_test_variation_header_domains` |
| 难度修饰套乘:空表零行为/套乘生效/越域 clamp | 难度曲线与Boss | `UnitContainer.spawn()` / `ConfigDbResolver.resolve_difficulty_modifiers()` | `table_structure_guard_test.gd:_smoke_difficulty_table` ; `config_db_resolver_test.gd:_test_difficulty_clamp` |
| Boss 出场门控(每区域恰一 Boss 终点/Boss 节点开战必选 Boss 行集) | 难度曲线与Boss | `NodeMapGenerator.generate()` / `BattleOrchestrator.begin_battle()` | `node_map_generator_test.gd:_test_boss_exit_per_region` ; `boss_gate_test.gd:_test_boss_node_spawns_boss_rowset` |
| 锻造表 schema 正反与几何价格梯 | 锻造工坊 | `ForgeTable.level_price()` / `ForgeTable.route_rows()` | `forge_table_test.gd:_test_production_rows` ; `forge_table_test.gd:_test_price_ladder` ; `forge_table_test.gd:_test_negative_cases` |
| 系统间契约词表与受理口径:五配方互异/掷点标签成员性/增益布尔受理 | 战斗结算×数据配置×增益状态 | `DamageController.open_ticket()` / `StatusContainer.apply_effect()` | `system_contracts_test.gd:_test_damage_controller_vocabularies` ; `system_contracts_test.gd:_test_rng_tag_closure` ; `system_contracts_test.gd:_test_status_boolean_acceptance` |
| 系统间契约词表与受理口径:五配方互异/掷点标签成员性/增益布尔受理 | 战斗结算×数据配置×增益状态 | `DamageController.open_ticket()` / `StatusContainer.apply_effect()` | `system_contracts_test.gd:_test_damage_controller_vocabularies` ; `system_contracts_test.gd:_test_rng_tag_closure` ; `system_contracts_test.gd:_test_status_boolean_acceptance` ; `source_guard_test.gd:_init` |
| 同名状态合并策略(叠加/累加/并存)与剩余次数语义 | 战斗循环×增益状态 | `StatusContainer.apply_effect()` (编排宿主 begin_battle 链) | `roll_multiplier_test.gd:_smoke_armor_roll` |
| 状态效果结算链(逐值衰减/到期移除/战斗结束全清/满层拒绝/独立并存/首授快照) | 增益状态 | `StatusContainer.apply_effect()` / `decay_round()` / `notify_battle_end()` | `system_contracts_test.gd:_test_status_decay_and_clear` ; `system_contracts_test.gd:_test_status_stack_full_reject` ; `system_contracts_test.gd:_test_status_independent_branch` ; `system_contracts_test.gd:_test_status_snapshot_first_grant` |
| 状态实例按个体归属:个体隔离/全体授予逐体发/死亡即清/同体合并照旧 | 增益状态 | `StatusContainer.apply_effect()` (个体键)/`purge_owner()` | `system_contracts_test.gd:_test_status_individual_isolation` ; `system_contracts_test.gd:_test_status_grant_all_per_unit` ; `system_contracts_test.gd:_test_status_death_clears` ; `system_contracts_test.gd:_test_status_merge_per_unit` |
@@ -243,15 +243,15 @@ tests/
## Running Tests
``` bash
# 冒烟测试(闸 00) ——极小启动场景,秒级
# 冒烟测试——极小启动场景,秒级
python tools/run_smoke.py
# 单元与集成测试(闸 02) ——Windows 须用 console 版 exe 取 stdout;工作目录 = game/(含 project.godot 那一层)
godot --headless --script tests/run_all.gd # 统一入口(本地闸 02 闸调用点)
# 单元与集成测试——Windows 须用 console 版 exe 取 stdout;工作目录 = game/(含 project.godot 那一层)
godot --headless --script tests/run_all.gd # 统一入口(本地单元与集成测试 闸调用点)
godot --headless --script tests/run_all.gd -- --only= battle_settlement # 选跑态——只跑路径含该词的套件(开发期最窄确认;零命中=用法错 exit 2,不产闸回执)
godot --headless --script tests/unit/example_test.gd
# 系统测试(闸 01) ——过渡期宿主 smoke_all.gd;分钟级
# 系统测试——过渡期宿主 smoke_all.gd;分钟级
python tools/run_system_test.py
# 场景探针(UI 探针层)——以探针场景为运行目标,走完整项目引导(autoload 在位)
@@ -332,7 +332,7 @@ S12 效果引擎无状态化旧件零残留:扫描 game/ 全域 `.gd` 与 `gam
## 本地闸(唯一验收门禁)
本仓库无远端、无 CI——**验收只在本地发生**,跑 `tools/run_all_gates.sh` 是收口唯一入口,按本批 改动域选档(`--code` / `--docs` /跨两域或改闸件本身=不带参数全量;代码域 02 按关联档选套件,回执 `scope` 字段记 full| related),
**验收=合回后远端 CI 闸全绿 ** ( 2026-11-03 用户裁,取代本地的合回验收;游戏码批=两域全量、02 全套件);`tools/run_all_gates.sh` 仍是全部验证闸的唯一入口与唯一清单,本地按 改动域选档跑批 ( `--code` / `--docs` /跨两域或改闸件本身=不带参数全量;代码域 02 按关联档选套件,回执 `scope` 字段记 full| related) 只服务开发期窄测,**不构成验收** ,
跑完写回执 `game/tests/.gates/receipt.json` (含 `domain` 与 `scope` 字段),合回 master 由 worktree-guard 按 diff 文件性质推域校验回执(`game/` 内 `.md` 归文档域)。
闸清单与域划分(含选闸算法与套件族映射表)的唯一定义处就是那个脚本,本文档不另列清单(清单散落多份文档正是历史漏跑闸的成因)。
@@ -346,6 +346,19 @@ S12 效果引擎无状态化旧件零残留:扫描 game/ 全域 `.gd` 与 `gam
**gdUnit4 维持 deferred ** :不引入第三方测试框架,本仓库在既有载体(`--script` 套件+场景运行目标)内解决。
## 闸门耗时基线(超时对比依据)
各闸在本机(Windows 基准档)的预期耗时区间与耗时模型。单次跑批实测显著超出区间上限(约 2× 中值)时,先核对环境因素(导入缓存重建、杀毒扫描、显示器休眠)再判性能回归。区间为单机粗测值;闸回执后续若记录实际耗时,以其积累值替换本表。
| 闸 | 耗时模型 | 预期区间 | 备注 |
|---|---|---|---|
| 00 冒烟 | O(1)——引擎启动一次+存活检查 | ~10–20 秒 | |
| 01 系统测试 | O(屏壳装配数 × 断言面规模) | ~2–3 分钟 | 断言计数随面浮动(口径见「断言计数双口径」节) |
| 02 单元与集成 | O(套件 manifest 条目数 × 单套件冷启动) | ~3–6 分钟 | 每套件独立子进程;单套件挂死守卫 120 秒 |
| 03 场景探针 | O(探针段数 × 引擎冷启动) | ~3– 5 分钟(--full/ --click 各计一次) | 耗时大头=每段一次引擎冷启动 |
| 05 渲染 | O(截图段数 × 窗口化冷启动 + golden 比对) | ~8–15 分钟 | 五段串行,需显示器在位 |
| 远端 CI 全量 | 上列各闸串联(两域全量) | ~30– 35 分钟 | 2026-11-04 远端 run 实测 ≈33 分钟(单点样本) |
## 术语(本项目内的唯一语义)
标准四级测试层(2026-10-22 用户裁,权威对照=design/gdd/术语表.md「退役词对照」):