Files
zeling_v2/Docs/Verification/03_Unit_StatusEffects.md

223 lines
7.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 单元测试 03 · 状态效果系统StatusEffects
> **测试类型**EditMode 单元测试NUnit
> **测试文件**`Assets/Tests/EditMode/StatusEffectTests.cs`(已存在,本文为完整规范)
> **被测程序集**`BaseGames.Combat.StatusEffects`
> **asmdef 依赖**`BaseGames.Tests.EditMode.asmdef` 需引用 `BaseGames.Combat.StatusEffects`
---
## 目录
1. [测试覆盖范围](#1-测试覆盖范围)
2. [现有测试验证](#2-现有测试验证)
3. [补充测试说明](#3-补充测试说明)
4. [完整扩展测试代码](#4-完整扩展测试代码)
5. [手动集成验证Play Mode](#5-手动集成验证play-mode)
---
## 1. 测试覆盖范围
| 类 | 测试点 |
|----|--------|
| `FireEffect` | MaxStacks=1MutualExclusions 含 FreezeOnStack 刷新持续时间EffectType=Fire |
| `PoisonEffect` | MaxStacks=3MutualExclusions 为空OnStack 增加 StackCount超限截断EffectType=Poison |
| `StaggerEffect` | MaxStacks=1BlockedBy 含 StunEffectType=Stagger |
| `StatusEffect` 基类 | IsExpired 在 Duration 耗尽后为 trueUpdate 正确减少剩余时间 |
| `StatusEffectManager` | ApplyEffect 正确添加;互斥效果自动移除;到期效果自动清理(需 MonoBehaviour Test 或接口 Mock |
---
## 2. 现有测试验证
项目已存在 `Assets/Tests/EditMode/StatusEffectTests.cs`,覆盖以下测试(共 14 个):
| 测试名 | 验证点 |
|--------|--------|
| `FireEffect_MaxStacks_IsOne` | FireEffect.MaxStacks == 1 |
| `PoisonEffect_MaxStacks_IsThree` | PoisonEffect.MaxStacks == 3 |
| `PoisonEffect_OnStack_IncreasesStackCount` | OnStack 后 StackCount == 2 |
| `PoisonEffect_OnStack_ClampsAtMaxStacks` | 多次叠加不超过 MaxStacks |
| `StaggerEffect_MaxStacks_IsOne` | StaggerEffect.MaxStacks == 1 |
| `FireEffect_MutualExclusions_ContainsFreeze` | MutualExclusions 含 Freeze |
| `PoisonEffect_MutualExclusions_IsEmpty` | PoisonEffect 无互斥 |
| `StaggerEffect_BlockedBy_ContainsStun` | BlockedBy 含 Stun |
| `FireEffect_BlockedBy_IsEmpty` | FireEffect 无阻断 |
| `StatusEffect_IsExpired_AfterDurationDepleted` | 时间耗尽后 IsExpired == true |
| `FireEffect_OnStack_RefreshDuration` | OnStack 刷新剩余时间 |
| `FireEffect_EffectType_IsFire` | EffectType == StatusEffectType.Fire |
| `PoisonEffect_EffectType_IsPoison` | EffectType == StatusEffectType.Poison |
| `StaggerEffect_EffectType_IsStagger` | EffectType == StatusEffectType.Stagger |
**运行现有测试步骤:**
1. 打开 `Window → General → Test Runner`
2. 选择 `EditMode` 标签页
3. 展开 `BaseGames.Tests.EditMode → StatusEffectTests`
4. 点击 `Run All`(或右键 `Run`
5. 确认所有 14 个测试 **全部绿色**
---
## 3. 补充测试说明
现有测试未覆盖以下场景,需补充:
### 3.1 StatusEffect.Update 时间精度
验证 `Update(delta)` 正确累计时间,不因浮点精度导致 IsExpired 判断提前/延迟。
### 3.2 多效果独立计时
同时持有 `FireEffect``PoisonEffect` 时,两个效果的剩余时间独立递减,互不影响。
### 3.3 OnApply / OnRemove 回调
`OnApply(owner)``OnRemove(owner)` 在正确时机被调用owner 可传 `null` 用于纯计时测试)。
### 3.4 StackCount 初始值
新建 Effect 时 `StackCount == 1`(已 Apply 一层)。
---
## 4. 完整扩展测试代码
将以下代码**追加**到现有 `StatusEffectTests.cs``}` 前,或创建新文件 `StatusEffectExtendedTests.cs`
```csharp
// 追加到 BaseGames.Tests.EditMode 命名空间下StatusEffectTests 类中
// ── 补充测试 ────────────────────────────────────────────────────────────────
[Test]
public void StatusEffect_StackCount_InitialValueIsOne()
{
var effect = new FireEffect();
Assert.AreEqual(1, effect.StackCount, "新建 Effect 的初始 StackCount 应为 1");
}
[Test]
public void StatusEffect_Update_RemainingTime_Decreases()
{
var effect = new StaggerEffect(2.0f);
effect.OnApply(null);
float initialDuration = effect.Duration;
effect.Update(0.5f);
Assert.Less(effect.Duration, initialDuration, "Update 后剩余时间应减少");
Assert.IsFalse(effect.IsExpired, "0.5s Update 后 2.0s 效果不应过期");
}
[Test]
public void StatusEffect_Update_ExactExpiry()
{
var effect = new StaggerEffect(1.0f);
effect.OnApply(null);
effect.Update(1.0f); // 恰好耗尽
Assert.IsTrue(effect.IsExpired, "恰好耗尽 duration 后应 IsExpired == true");
}
[Test]
public void MultipleEffects_IndependentTimers()
{
var fire = new FireEffect();
var poison = new PoisonEffect();
fire.OnApply(null);
poison.OnApply(null);
float fireDuration = fire.Duration;
float poisonDuration = poison.Duration;
fire.Update(0.5f);
// poison 未调用 Update时间不应变化
Assert.AreEqual(poisonDuration, poison.Duration, 0.0001f,
"未 Update 的 Effect 持续时间不应减少");
Assert.Less(fire.Duration, fireDuration, "已 Update 的 Effect 持续时间应减少");
}
[Test]
public void PoisonEffect_OnStack_DoesNotExceedMaxStacks_EdgeCase()
{
var effect = new PoisonEffect();
// MaxStacks = 3初始 StackCount = 1再叠加 2 次达到上限
effect.OnStack();
effect.OnStack();
Assert.AreEqual(3, effect.StackCount);
// 再叠加,不应超过 3
effect.OnStack();
effect.OnStack();
Assert.AreEqual(3, effect.StackCount, "StackCount 不应超过 MaxStacks");
}
[Test]
public void FireEffect_OnApply_ThenRemove_DoesNotThrow()
{
var effect = new FireEffect();
Assert.DoesNotThrow(() =>
{
effect.OnApply(null);
effect.OnRemove(null);
});
}
```
---
## 5. 手动集成验证Play Mode
以下场景需要在 Unity Editor 中手动测试(无法在 EditMode 测试中验证):
### 5.1 StatusEffectManager 添加效果
**前提条件**:测试场景中有玩家或敌人,其 GameObject 挂有 `StatusEffectManager` 组件。
**步骤:**
1. 进入 Play Mode
2. 在 Inspector 中找到目标对象的 `StatusEffectManager` 组件
3. 通过 Console 调用(或临时测试按钮):`statusEffectManager.Apply(new PoisonEffect())`
4. 在 Console 中观察 Poison 效果 Tick 日志(每 `tickInterval` 秒一条)
**预期结果:**
- Poison 效果持续 `duration`
- 每次 Tick 扣减目标 HP
- 到期后自动从管理器移除,不再 Tick
### 5.2 互斥效果测试
**步骤:**
1. 对同一目标施加 `FireEffect`
2. 随后施加 `FreezeEffect`FireEffect 的 MutualExclusion
**预期结果:**
- `FireEffect` 被自动移除
- Console 无 `NullReferenceException`
### 5.3 效果叠加Poison
**步骤:**
1. 对目标施加 `PoisonEffect`StackCount = 1
2. 再施加一次 `PoisonEffect`
3. 再施加一次StackCount 达到 3
4. 再施加一次(超过上限)
**预期结果:**
- StackCount 分别变为 2、3、3截断
- Inspector 中 `StatusEffectManager` 显示正确的 StackCount
### 5.4 阻断效果StaggerEffect BlockedBy Stun
**步骤:**
1. 对目标先施加 `StunEffect`
2. 尝试施加 `StaggerEffect`
**预期结果:**
- `StaggerEffect` 被阻断,未添加到管理器
- Console 无报错