Unity单元测试初始化失败排查:空引用错误与测试模式选择
问题解决与模式选择
一、NullReferenceException 问题修复
你遇到的报错并非playerNameInput2本身为null,而是TMP组件创建时缺少必要的依赖对象:直接通过AddComponent<TMP_InputField>()添加的组件,其内部用于显示文本的textComponent并未自动生成,导致访问.text属性时触发空引用异常。
修复后的测试代码
using System.Collections; using NUnit.Framework; using TMPro; using UnityEngine; using UnityEngine.TestTools; using UnityEngine.UI; public class Playtests_StartScene { [UnityTest] public IEnumerator Start_InitializesUIElements() { // 创建测试对象并挂载脚本 GameObject startSceneObject = new GameObject(); var startSceneScript = startSceneObject.AddComponent<StartSceneScript>(); // 初始化TMP_InputField1并关联文本载体 var input1 = startSceneObject.AddComponent<TMP_InputField>(); var input1Text = new GameObject("Input1Text").AddComponent<TextMeshProUGUI>(); input1Text.transform.SetParent(startSceneObject.transform); input1.textComponent = input1Text; startSceneScript.playerNameInput1 = input1; // 初始化TMP_InputField2并关联文本载体 var input2 = startSceneObject.AddComponent<TMP_InputField>(); var input2Text = new GameObject("Input2Text").AddComponent<TextMeshProUGUI>(); input2Text.transform.SetParent(startSceneObject.transform); input2.textComponent = input2Text; startSceneScript.playerNameInput2 = input2; // 初始化所有TMP_Text组件 var warningText = new GameObject("WarningText").AddComponent<TMP_Text>(); warningText.transform.SetParent(startSceneObject.transform); startSceneScript.warningText = warningText; var blueShipText = new GameObject("BlueShipText").AddComponent<TMP_Text>(); blueShipText.transform.SetParent(startSceneObject.transform); startSceneScript.blueShipCountText = blueShipText; var redShipText = new GameObject("RedShipText").AddComponent<TMP_Text>(); redShipText.transform.SetParent(startSceneObject.transform); startSceneScript.redShipCountText = redShipText; // 初始化Slider组件(设置value无需额外子组件) startSceneScript.blueShipCountSlider = startSceneObject.AddComponent<Slider>(); startSceneScript.redShipCountSlider = startSceneObject.AddComponent<Slider>(); // 调用Start方法 startSceneScript.Start(); // 断言验证初始化结果 Assert.AreEqual("Blue Team", startSceneScript.playerNameInput1.text); Assert.AreEqual("Red Team", startSceneScript.playerNameInput2.text); Assert.AreEqual("", startSceneScript.warningText.text); Assert.AreEqual(1, Mathf.RoundToInt(startSceneScript.blueShipCountSlider.value)); Assert.AreEqual(1, Mathf.RoundToInt(startSceneScript.redShipCountSlider.value)); Assert.AreEqual("1", startSceneScript.blueShipCountText.text); Assert.AreEqual("1", startSceneScript.redShipCountText.text); yield return null; } }
额外优化建议
在StartSceneScript中添加空引用检查,避免实际运行时因组件未赋值报错:
public void Start() { playerNameInput1?.text = "Blue Team"; playerNameInput2?.text = "Red Team"; warningText?.text = ""; blueShipCountSlider?.SetValueWithoutNotify(1); redShipCountSlider?.SetValueWithoutNotify(1); ShowSliderValue(); } public void ShowSliderValue() { if (blueShipCountSlider != null) GlobalVariables.blueShipsCount = Mathf.RoundToInt(blueShipCountSlider.value); if (redShipCountSlider != null) GlobalVariables.redShipsCount = Mathf.RoundToInt(redShipCountSlider.value); blueShipCountText?.text = GlobalVariables.blueShipsCount.ToString(); redShipCountText?.text = GlobalVariables.redShipsCount.ToString(); }
二、编辑器模式 vs Play模式测试选择
针对你的UI初始化逻辑测试场景,两种模式的适用场景如下:
- 编辑器模式测试:
优势:无需启动Play模式,执行速度快;可直接访问编辑器API,适合测试场景序列化、资源加载类逻辑。
劣势:无法模拟完整运行时环境,依赖生命周期的逻辑测试准确性不足。 - Play模式测试:
优势:完全模拟游戏运行时状态,能准确验证组件生命周期(如Start)、UI交互等逻辑,匹配你的测试需求。
劣势:启动Play模式会增加测试执行时间。
结论:你的测试场景更适合使用Play模式测试,它能确保测试结果与实际游戏运行状态完全一致。
内容的提问来源于stack exchange,提问作者Jaydek
相关产品推荐
相关产品推荐

