Unity UIToolkit运行模式单元测试中按钮点击事件未触发
Unity UIToolkit按钮单元测试点击事件不触发问题
问题描述
我用Unity的UIToolkit制作了一个简单菜单系统,核心是点击后切换场景的开始按钮。该按钮在测试场景中功能正常,但编写对应的运行模式单元测试时,测试无法检测到按钮的点击事件。
初始测试用例代码
[UnityTest] public IEnumerator TestButtonClick() { bool clicked = false; startButton.clicked += () => { clicked = true; Debug.Log("Button clicked!"); // 用于检查点击事件是否触发的日志 }; startButton.SetEnabled(true); startButton.style.display = DisplayStyle.Flex; var pickingMode = startButton.pickingMode; Debug.Log($"Button picking mode: {pickingMode}"); var displayStyle = startButton.resolvedStyle.display; Debug.Log($"Button display style: {displayStyle}"); yield return null; var root = startButton.hierarchy.parent; if (root != null) { Debug.Log($"Button's parent is: {root}"); } else { Debug.LogError("The button has no parent in the hierarchy."); } Debug.Log($"Button is interactable: {startButton.enabledSelf}"); // 模拟PointerDownEvent using (var pointerDownEvent = new PointerDownEvent()) { pointerDownEvent.target = startButton; // 确保事件目标是正确的按钮 startButton.SendEvent(pointerDownEvent); // 日志检查事件是否被接收 Debug.Log($"PointerDownEvent target: {pointerDownEvent.target}"); Assert.IsFalse(pointerDownEvent.isPropagationStopped, "PointerDownEvent传播意外停止。"); } yield return new WaitForSeconds(0.1f); // 按下和抬起事件之间的短延迟 // 模拟PointerUpEvent using (var pointerUpEvent = new PointerUpEvent()) { pointerUpEvent.target = startButton; // 确保事件目标是正确的按钮 startButton.SendEvent(pointerUpEvent); // 日志检查事件是否被接收 Debug.Log($"PointerUpEvent target: {pointerUpEvent.target}"); Assert.IsFalse(pointerUpEvent.isPropagationStopped, "PointerUpEvent传播意外停止。"); } yield return null; // 断言按钮点击事件已触发 if (!clicked) { Debug.LogError("按钮点击事件未触发。"); } // 断言按钮点击事件已触发 Assert.IsTrue(clicked, "按钮点击事件未触发。"); }
测试日志输出
TestButtonClick (0.201s) --- Unhandled log message: '[Error] 按钮点击事件未触发。'. Use UnityEngine.TestTools.LogAssert.Expect --- UI_tests/<TestButtonClick>d__6:MoveNext () (at Assets/Tests/UI_tests.cs:121) UnityEngine.SetupCoroutine:InvokeMoveNext (System.Collections.IEnumerator,intptr) --- Button picking mode: Position Button display style: Flex Button's parent is: VisualElement Buttons (x:0.00, y:0.00, width:NaN, height:NaN) world rect: (x:0.00, y:0.00, width:NaN, height:NaN) Button is interactable: True PointerDownEvent target: Button Play (x:0.00, y:0.00, width:NaN, height:NaN) world rect: (x:0.00, y:0.00, width:NaN, height:NaN) PointerUpEvent target: Button Play (x:0.00, y:0.00, width:NaN, height:NaN) world rect: (x:0.00, y:0.00, width:NaN, height:NaN) 按钮点击事件未触发。
菜单UXML代码
<engine:UXML xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:engine="UnityEngine.UIElements" xmlns:editor="UnityEditor.UIElements" noNamespaceSchemaLocation="../../UIElementsSchema/UIElements.xsd" editor-extension-mode="False"> <Style src="project://database/Assets/UI/MenuStyles.uss?fileID=7433441132597879392&guid=446f70e76c5306241815d1b7f67264e1&type=3#MenuStyles" /> <engine:VisualElement name="LeftSection" style="flex-grow: 1; background-color: rgb(0, 0, 0); width: 45%; height: 100%; margin-left: 50px;"> <engine:VisualElement name="Buttons" style="flex-grow: 1; justify-content: center; padding-left: 20%; padding-right: 20%; padding-top: 20%; padding-bottom: 20%;"> <engine:Button text="Play" name="Play" class="menu-button" /> <engine:Button text="Settings" name="Settings" class="menu-button" /> <engine:Button text="Rotate" name="Rotate" class="menu-button" /> <engine:Button text="Exit" name="Exit" class="menu-button" /> </engine:VisualElement> </engine:VisualElement> </engine:UXML>
后续测试对比
通过代码直接创建UIDocument和按钮时,测试能正常检测到点击事件;但加载自定义Menu.UXML的VisualTree时,点击事件无法触发。以下是两个对比测试用例:
正常通过的测试(代码创建UI)
[UnityTest] public IEnumerator TestClick2() { bool wasClicked = false; Button btn = new Button { name = "foobar" }; btn.RegisterCallback<ClickEvent>(_ => wasClicked = true); GameObject hostGameObject = new GameObject(); UIDocument uiDoc = hostGameObject.AddComponent<UIDocument>(); uiDoc.panelSettings = ScriptableObject.CreateInstance<PanelSettings>(); uiDoc.rootVisualElement.Add(btn); yield return null; using (ClickEvent clkEvt = ClickEvent.GetPooled()) { clkEvt.target = btn; btn.SendEvent(clkEvt); } Assert.IsTrue(wasClicked); }
失败的测试(加载UXML)
[UnityTest] public IEnumerator TestClick3() { var uiDocument = new GameObject().AddComponent<UIDocument>(); // 加载指定的UXML文件 var visualTree = Resources.Load<VisualTreeAsset>("Menu"); if (visualTree != null) { uiDocument.visualTreeAsset = visualTree; } if (visualTree == null) { Debug.LogError("Visual Tree为空,无法从Resources加载"); } yield return null; root = uiDocument.rootVisualElement; yield return null; startButton = root.Q<Button>("Play"); if (startButton == null) { Debug.LogError("未找到Play按钮。"); } Debug.Log("startButton是: " + startButton); Assert.NotNull(startButton, "start button为空"); bool wasClicked = false; startButton.SetEnabled(true); startButton.style.display = DisplayStyle.Flex; startButton.RegisterCallback<ClickEvent>(_ => wasClicked = true); yield return null; using (ClickEvent clkEvt = ClickEvent.GetPooled()) { clkEvt.target = startButton; startButton.SendEvent(clkEvt); } Assert.IsTrue(wasClicked); }
内容的提问来源于stack exchange,提问作者Markus T.
相关产品推荐
相关产品推荐

