using System.Collections; using NUnit.Framework; using UnityEngine; using UnityEngine.TestTools; using BaseGames.Enemies; using BaseGames.Enemies.Abilities; namespace BaseGames.Tests.EditMode.Enemies { public class BossPhaseAbilityGateTests { /// 最小可实例化能力:不播动画、不碰 HitBox,只为验证启停与 CanUse。 private sealed class StubAbility : EnemyAbilityBase { /// /// 编辑模式下 Unity 不会在 AddComponent 时调用 Awake,_enemy 会留空导致 CanUse 恒假。 /// 这里手动跑一次真实的 Awake(而非反射直写字段),让依赖解析走生产代码路径。 /// public void RunAwake() => Awake(); protected override IEnumerator ExecuteCoroutine() { yield break; } } /// 测试期建出的宿主对象;在 TearDown 统一销毁,断言失败也不会残留到编辑器场景。 private GameObject _host; // RunAwake 时 EnemyAbilityBase 找不到 AnimancerComponent 会告警,与本测试无关。 [SetUp] public void SetUp() => LogAssert.ignoreFailingMessages = true; [TearDown] public void TearDown() { // 项目关闭了 Domain/Scene Reload:断言失败会跳过用例后续语句, // 清理必须放在 TearDown,否则失败一次就往编辑器场景里漏一个对象。 if (_host != null) Object.DestroyImmediate(_host); _host = null; LogAssert.ignoreFailingMessages = false; } [Test] public void DisabledAbility_IsNotUsable() { // 必须先挂 EnemyBase:否则 _enemy==null 会让 CanUse 恒假, // 这条断言在修复前也会"通过",成为一个永远不会失败的测试。 _host = new GameObject("ability-host"); _host.AddComponent(); // 裸 EnemyBase 的 _currentState=Controlled → IsAlive 为真 var ab = _host.AddComponent(); ab.RunAwake(); // 编辑模式不自动跑 Awake,手动解析 _enemy Assert.IsTrue(ab.CanUse, "前提:启用且宿主存活时应可用——否则下一条断言分不清是 enabled 还是别的门在起作用"); ab.enabled = false; Assert.IsFalse(ab.CanUse, "禁用的能力组件不可用——否则选招器会选中一个启不动招的招"); } } }