UI相关优化补充
This commit is contained in:
8
Assets/Tests/PlayMode.meta
Normal file
8
Assets/Tests/PlayMode.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 71c6d91864f353542af76dc4bdd78175
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
24
Assets/Tests/PlayMode/BaseGames.Tests.PlayMode.asmdef
Normal file
24
Assets/Tests/PlayMode/BaseGames.Tests.PlayMode.asmdef
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"name": "BaseGames.Tests.PlayMode",
|
||||
"rootNamespace": "BaseGames.Tests.PlayMode",
|
||||
"references": [
|
||||
"BaseGames.Core",
|
||||
"BaseGames.Core.Events",
|
||||
"BaseGames.UI",
|
||||
"UnityEngine.TestRunner",
|
||||
"Unity.TextMeshPro"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": true,
|
||||
"precompiledReferences": [
|
||||
"nunit.framework.dll"
|
||||
],
|
||||
"autoReferenced": false,
|
||||
"defineConstraints": [
|
||||
"UNITY_INCLUDE_TESTS"
|
||||
],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ba2164f377b449148960bb029fea13e7
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
37
Assets/Tests/PlayMode/ColorblindApplierTests.cs
Normal file
37
Assets/Tests/PlayMode/ColorblindApplierTests.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using System.Collections;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
using UnityEngine.TestTools;
|
||||
using BaseGames.Core;
|
||||
using BaseGames.UI.Utility;
|
||||
|
||||
namespace BaseGames.Tests.PlayMode
|
||||
{
|
||||
/// <summary>
|
||||
/// ColorblindApplier 测试:写入 Shader 全局变量。
|
||||
/// </summary>
|
||||
public class ColorblindApplierTests
|
||||
{
|
||||
private GameObject _host;
|
||||
|
||||
[SetUp] public void SetUp() { _host = new GameObject("ColorblindHost"); }
|
||||
[TearDown] public void TearDown() { Object.DestroyImmediate(_host); }
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator ApplyMode_WritesShaderGlobals()
|
||||
{
|
||||
var applier = _host.AddComponent<ColorblindApplier>();
|
||||
applier.ApplyMode(ColorblindMode.Deuteranopia);
|
||||
yield return null;
|
||||
Assert.AreEqual((int)ColorblindMode.Deuteranopia,
|
||||
Shader.GetGlobalInt(Shader.PropertyToID("_GlobalColorblindMode")));
|
||||
Assert.AreEqual(1f,
|
||||
Shader.GetGlobalFloat(Shader.PropertyToID("_GlobalColorblindStrength")), 0.001f);
|
||||
|
||||
applier.ApplyMode(ColorblindMode.None);
|
||||
yield return null;
|
||||
Assert.AreEqual(0,
|
||||
Shader.GetGlobalInt(Shader.PropertyToID("_GlobalColorblindMode")));
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Tests/PlayMode/ColorblindApplierTests.cs.meta
Normal file
11
Assets/Tests/PlayMode/ColorblindApplierTests.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 07ca55485ed3db14e822d55d1116e5d3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
49
Assets/Tests/PlayMode/RequiredFieldValidatorTests.cs
Normal file
49
Assets/Tests/PlayMode/RequiredFieldValidatorTests.cs
Normal file
@@ -0,0 +1,49 @@
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
using BaseGames.Core;
|
||||
|
||||
namespace BaseGames.Tests.PlayMode
|
||||
{
|
||||
/// <summary>
|
||||
/// RequiredFieldValidator 反射扫描测试。
|
||||
/// </summary>
|
||||
public class RequiredFieldValidatorTests
|
||||
{
|
||||
private class Sample : MonoBehaviour
|
||||
{
|
||||
[RequiredField] public GameObject Required;
|
||||
[RequiredField("提示文本")] public string RequiredString;
|
||||
public GameObject Optional;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void MissingField_LogsWarning()
|
||||
{
|
||||
var go = new GameObject("ReqHost");
|
||||
var s = go.AddComponent<Sample>();
|
||||
s.Required = null;
|
||||
s.RequiredString = "";
|
||||
|
||||
// 期待两条警告(Required + RequiredString)
|
||||
UnityEngine.TestTools.LogAssert.Expect(LogType.Warning,
|
||||
new System.Text.RegularExpressions.Regex(@"\[RequiredField\] Sample\.Required.*"));
|
||||
UnityEngine.TestTools.LogAssert.Expect(LogType.Warning,
|
||||
new System.Text.RegularExpressions.Regex(@"\[RequiredField\] Sample\.RequiredString.*"));
|
||||
RequiredFieldValidator.ValidateAll(s);
|
||||
|
||||
Object.DestroyImmediate(go);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FilledField_NoWarning()
|
||||
{
|
||||
var go = new GameObject("ReqHost2");
|
||||
var s = go.AddComponent<Sample>();
|
||||
s.Required = go;
|
||||
s.RequiredString = "ok";
|
||||
|
||||
RequiredFieldValidator.ValidateAll(s); // 不应有警告
|
||||
Object.DestroyImmediate(go);
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Tests/PlayMode/RequiredFieldValidatorTests.cs.meta
Normal file
11
Assets/Tests/PlayMode/RequiredFieldValidatorTests.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5afa9356c16c2954f899e0d092be37b3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
79
Assets/Tests/PlayMode/ToastManagerTests.cs
Normal file
79
Assets/Tests/PlayMode/ToastManagerTests.cs
Normal file
@@ -0,0 +1,79 @@
|
||||
using System.Collections;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityEngine.TestTools;
|
||||
using TMPro;
|
||||
using BaseGames.UI;
|
||||
|
||||
namespace BaseGames.Tests.PlayMode
|
||||
{
|
||||
/// <summary>
|
||||
/// ToastManager 队列行为测试:
|
||||
/// · Enqueue 一条后 Toast 激活并最终隐藏
|
||||
/// · 连续 Enqueue 3 条按序串行播放
|
||||
///
|
||||
/// 不依赖事件频道(直接调用 Enqueue),不依赖本地化(标题/正文为常量字符串)。
|
||||
/// </summary>
|
||||
public class ToastManagerTests
|
||||
{
|
||||
private GameObject _host;
|
||||
private ToastManager _mgr;
|
||||
private ToastNotification _toast;
|
||||
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
_host = new GameObject("ToastHost");
|
||||
|
||||
// Toast 预制:CanvasGroup + 子文本
|
||||
var toastGO = new GameObject("Toast", typeof(CanvasGroup));
|
||||
toastGO.transform.SetParent(_host.transform);
|
||||
toastGO.SetActive(false);
|
||||
_toast = toastGO.AddComponent<ToastNotification>();
|
||||
// 反射注入 _displayDuration / _fadeDuration 减为短值,缩短测试时长
|
||||
SetPrivate(_toast, "_displayDuration", 0.05f);
|
||||
SetPrivate(_toast, "_fadeDuration", 0.02f);
|
||||
|
||||
_mgr = _host.AddComponent<ToastManager>();
|
||||
SetPrivate(_mgr, "_toast", _toast);
|
||||
_host.SetActive(false);
|
||||
_host.SetActive(true); // 触发 Awake/OnEnable
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void TearDown() { Object.DestroyImmediate(_host); }
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator Enqueue_ShowsThenHides()
|
||||
{
|
||||
_mgr.Enqueue("T", "B", null);
|
||||
yield return null;
|
||||
Assert.IsTrue(_toast.gameObject.activeSelf, "入队后 Toast 应当激活");
|
||||
|
||||
// 总时长 ~= 0.02+0.05+0.02 = 0.09s,再 + 队列等待 0.1s
|
||||
yield return new WaitForSecondsRealtime(0.5f);
|
||||
Assert.IsFalse(_toast.gameObject.activeSelf, "Toast 自动隐藏未生效");
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator MultipleEnqueue_PlaysSerially()
|
||||
{
|
||||
_mgr.Enqueue("A", "1", null);
|
||||
_mgr.Enqueue("B", "2", null);
|
||||
yield return null;
|
||||
Assert.IsTrue(_toast.gameObject.activeSelf, "第一条应当立即播放");
|
||||
// 不严格验证内容(涉及私有字段),只验证活动状态推进。
|
||||
yield return new WaitForSecondsRealtime(1.0f);
|
||||
Assert.IsFalse(_toast.gameObject.activeSelf, "两条串行播放后应当全部结束");
|
||||
}
|
||||
|
||||
// ── 反射工具 ──────────────────────────────────────────────────────
|
||||
private static void SetPrivate(object target, string fieldName, object value)
|
||||
{
|
||||
var f = target.GetType().GetField(fieldName,
|
||||
System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
|
||||
f?.SetValue(target, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Tests/PlayMode/ToastManagerTests.cs.meta
Normal file
11
Assets/Tests/PlayMode/ToastManagerTests.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ee01b829ae0f99445b90f0561e2ccae1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
94
Assets/Tests/PlayMode/UIManagerSmokeTest.cs
Normal file
94
Assets/Tests/PlayMode/UIManagerSmokeTest.cs
Normal file
@@ -0,0 +1,94 @@
|
||||
using System.Collections;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
using UnityEngine.TestTools;
|
||||
using BaseGames.UI;
|
||||
|
||||
namespace BaseGames.Tests.PlayMode
|
||||
{
|
||||
/// <summary>
|
||||
/// UIManager 烟雾测试:验证面板栈基本不变式。
|
||||
///
|
||||
/// 覆盖:
|
||||
/// · OpenPanel → CloseTopPanel 后栈为空;
|
||||
/// · 嵌套打开(A → B → CloseTop)后 A 仍处于激活态;
|
||||
/// · 重复 OpenPanel 同一面板不会双压栈(HashSet 去重)。
|
||||
///
|
||||
/// 注:测试只覆盖框架行为,不验证业务面板(CharmPanel 等)的内部逻辑。
|
||||
/// </summary>
|
||||
public class UIManagerSmokeTest
|
||||
{
|
||||
private GameObject _hostGO;
|
||||
private UIManager _manager;
|
||||
private GameObject _panelA;
|
||||
private GameObject _panelB;
|
||||
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
_hostGO = new GameObject("UIManager_Host");
|
||||
_manager = _hostGO.AddComponent<UIManager>();
|
||||
_panelA = new GameObject("PanelA");
|
||||
_panelB = new GameObject("PanelB");
|
||||
_panelA.SetActive(false);
|
||||
_panelB.SetActive(false);
|
||||
|
||||
// 强制 OnEnable 触发(AddComponent 同帧已触发,这里二次启用保证 ServiceLocator 状态)
|
||||
_hostGO.SetActive(false);
|
||||
_hostGO.SetActive(true);
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void TearDown()
|
||||
{
|
||||
Object.DestroyImmediate(_panelA);
|
||||
Object.DestroyImmediate(_panelB);
|
||||
Object.DestroyImmediate(_hostGO);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator OpenThenCloseTop_PanelDeactivated()
|
||||
{
|
||||
_manager.OpenPanel(_panelA);
|
||||
yield return null;
|
||||
|
||||
Assert.IsTrue(_panelA.activeSelf, "OpenPanel 应当激活面板");
|
||||
|
||||
_manager.CloseTopPanel();
|
||||
yield return null;
|
||||
|
||||
Assert.IsFalse(_panelA.activeSelf, "CloseTopPanel 应当反激活栈顶面板");
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator NestedOpen_PreviousPanelHiddenAndRestored()
|
||||
{
|
||||
_manager.OpenPanel(_panelA);
|
||||
_manager.OpenPanel(_panelB);
|
||||
yield return null;
|
||||
|
||||
Assert.IsFalse(_panelA.activeSelf, "嵌套打开时上一层应被隐藏");
|
||||
Assert.IsTrue(_panelB.activeSelf, "新打开的面板应当激活");
|
||||
|
||||
_manager.CloseTopPanel();
|
||||
yield return null;
|
||||
|
||||
Assert.IsTrue(_panelA.activeSelf, "关闭栈顶后上一层应当恢复");
|
||||
Assert.IsFalse(_panelB.activeSelf, "关闭后栈顶面板应当反激活");
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator DoubleOpenSamePanel_NoStackDuplication()
|
||||
{
|
||||
_manager.OpenPanel(_panelA);
|
||||
_manager.OpenPanel(_panelA);
|
||||
yield return null;
|
||||
|
||||
// 关闭一次后栈应为空
|
||||
_manager.CloseTopPanel();
|
||||
yield return null;
|
||||
|
||||
Assert.IsFalse(_panelA.activeSelf, "重复打开应被去重;关闭一次后即应隐藏");
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Tests/PlayMode/UIManagerSmokeTest.cs.meta
Normal file
11
Assets/Tests/PlayMode/UIManagerSmokeTest.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 953f5cb03f10b1d4db3d8da7121ba910
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
60
Assets/Tests/PlayMode/UITweenTests.cs
Normal file
60
Assets/Tests/PlayMode/UITweenTests.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
using System.Collections;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityEngine.TestTools;
|
||||
using BaseGames.UI;
|
||||
|
||||
namespace BaseGames.Tests.PlayMode
|
||||
{
|
||||
/// <summary>
|
||||
/// UITween 静态库测试:验证补间在终态吸附、零时长立即返回、null 安全。
|
||||
/// </summary>
|
||||
public class UITweenTests
|
||||
{
|
||||
private GameObject _go;
|
||||
|
||||
[SetUp] public void SetUp() { _go = new GameObject("TweenHost", typeof(RectTransform), typeof(CanvasGroup)); }
|
||||
[TearDown] public void TearDown() { Object.DestroyImmediate(_go); }
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator MoveAnchored_ReachesTarget()
|
||||
{
|
||||
var rect = _go.GetComponent<RectTransform>();
|
||||
rect.anchoredPosition = Vector2.zero;
|
||||
yield return _go.AddComponent<TestRunner>().Run(UITween.MoveAnchored(rect, new Vector2(100, 50), 0.05f));
|
||||
Assert.AreEqual(new Vector2(100, 50), rect.anchoredPosition);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator FadeCanvasGroup_ReachesTarget()
|
||||
{
|
||||
var cg = _go.GetComponent<CanvasGroup>();
|
||||
cg.alpha = 0f;
|
||||
yield return _go.AddComponent<TestRunner>().Run(UITween.FadeCanvasGroup(cg, 1f, 0.05f));
|
||||
Assert.AreEqual(1f, cg.alpha, 0.001f);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator ZeroDuration_SnapsImmediately()
|
||||
{
|
||||
var rect = _go.GetComponent<RectTransform>();
|
||||
yield return _go.AddComponent<TestRunner>().Run(UITween.MoveAnchored(rect, new Vector2(7, 7), 0f));
|
||||
Assert.AreEqual(new Vector2(7, 7), rect.anchoredPosition);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator NullTarget_NoException()
|
||||
{
|
||||
yield return _go.AddComponent<TestRunner>().Run(UITween.MoveAnchored(null, Vector2.one, 0.05f));
|
||||
yield return _go.AddComponent<TestRunner>().Run(UITween.FadeCanvasGroup(null, 1f, 0.05f));
|
||||
Assert.Pass();
|
||||
}
|
||||
|
||||
/// <summary>挂宿主跑协程的辅助 MonoBehaviour(测试场景无 EventSystem)。</summary>
|
||||
private class TestRunner : MonoBehaviour
|
||||
{
|
||||
public IEnumerator Run(IEnumerator inner) { yield return StartCoroutine(inner); }
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Tests/PlayMode/UITweenTests.cs.meta
Normal file
11
Assets/Tests/PlayMode/UITweenTests.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 65492216fce745f41b6a7352763938e2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user