多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

Unity3DTraining 实战:使用 Editor Test Runner 为 Unity 游戏逻辑编写单元测试

Unity3DTraining 实战:使用 Editor Test Runner 为 Unity 游戏逻辑编写单元测试 示例工程【免费下载链接】Unity3DTraining【Unity杂货铺】unity大杂烩~项目地址https://gitcode.com/gh_mirrors/un/Unity3DTraining点击查看免费下载本篇指南围绕 Unity3DTraining 仓库中Unit4Unity/Editor Test Runner示例工程系统讲解如何借助 Unity 内置的 Editor Test Runner编辑器测试运行器为游戏核心逻辑编写单元测试。你将掌握测试工程的目录组织、NUnit 断言与异常测试的写法、如何用故意写错的用例验证测试有效性以及如何在 Unity 5.x 编辑器中一键运行全部测试把单元测试真正落到日常游戏开发流程中。为什么游戏逻辑也需要单元测试游戏项目里的血量、伤害、道具、背包等纯逻辑代码往往随着版本迭代不断被修改。如果没有自动化验证一次改动就可能悄悄破坏已有功能而人工回归测试又很难覆盖所有边界分支。单元测试的价值在于把这段逻辑的结果是否符合预期变成可反复执行的机器判定。在 Unity3DTraining 仓库中Unit4Unity/Editor Test Runner 目录就是为此准备的完整示例——它演示了如何用 Unity 自带的 Editor Test Runner NUnit 框架对玩家Player血量增减、负数血量异常等核心逻辑进行自动化测试。阅读完本篇你可以在自己的 Unity 工程里复刻这套流程。认识 Editor Test Runner 与测试框架Unity 从 5.x 时代起就内置了Editor Test Runner它基于成熟的NUnit测试框架与 .NET 生态同源让开发者无需引入第三方测试工具即可在编辑器中运行单元测试。该示例工程为此在Assets/Plugins目录下放置了 Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll工程文件中也可以看到对该程序集的显式引用Reference IncludeMicrosoft.VisualStudio.QualityTools.UnitTestFramework HintPathAssets\Plugins\Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll/HintPath /Reference从 Editor Test Runner.CSharp.csproj 还可以看到测试工程同时引用了UnityEngine.PlaymodeTestsRunner与UnityEditor说明测试运行器是编辑器运行时Edit Mode能力的一部分。在 Unity 5.5 中通过菜单Window → Editor Tests Runner打开测试窗口新版本 Unity 则位于Window → General → Test Runner。点击Run All即可执行编辑器模式下所有带[Test]特性的方法。测试工程的关键目录约定示例工程的文件结构遵循了 Unity 测试的硬性约定这是能否被 Test Runner 识别的关键Unit4Unity/Editor Test Runner/ ├── Assets/ │ ├── Editor/ # 编辑器测试代码统一放在 Editor 目录下 │ │ ├── Player.cs │ │ ├── NegativeHealthException.cs │ │ ├── PlayerTest.cs │ │ └── PlayerTestWrong.cs │ ├── Plugins/ # NUnit 测试框架程序集 │ ├── Scenes/Demo.unity ├── ProjectSettings/ # 工程配置Unity 5.5.0f3要点测试脚本必须放在Editor文件夹内或其子目录。Editor 文件夹中的脚本只在编辑器下编译运行不会打进游戏发布包天然适合存放测试代码该目录下的代码也因此在csproj中被单独编译。被测对象Player是纯 C# 类不依赖场景对象测试可以直接new Player()使用这也是单元测试倡导的可独立验证设计。示例工程基于Unity 5.5.0f3见 ProjectVersion.txtEditor Test Runner 在后续版本中持续保留并演进核心 API 与使用方式一致。被测代码一个带血量和异常的 Player 类首先看被测目标 Player.cs。它定义了一个极简的玩家血量模型public class Player{ public float Health { get; set; } #region 正确的方法 public void Damage(float value) { Health - value; if (Health 0) { throw new NegativeHealthException(); } } public void Recover(float value) { Health value; } #endregion #region 错误的方法 public void DamageWrong(float value) { Health - value 1; } public void DamageNoException(float value) { Health - value; } #endregion }设计上它包含两组方法方便对照正确实现Damage扣血后若血量小于 0 会抛出NegativeHealthExceptionRecover加血。这是业务上的约束——角色血量不允许为负。错误实现故意埋坑DamageWrong多扣了 1 点血value 1是刻意引入的差一错误DamageNoException扣到负数也不抛异常违背了业务约束。对应的自定义异常 NegativeHealthException.cs 继承自ApplicationException/// summary /// 自定义的异常类型 /// /summary class NegativeHealthException : ApplicationException { }这套正确实现 故意写错的实现组合正是验证测试用例本身是否有效的手段——好的测试必须能抓住 bug。编写第一个测试类断言正确行为PlayerTest.cs 是核心测试类通过using NUnit.Framework;引入测试 APIusing NUnit.Framework; public class PlayerTest{ [Test] public void TestHealth() { Player player new Player(); player.Health 1000.0f; //通过Assert断言来判断这个函数的返回结果是否符合预期 player.Damage(200); Assert.AreEqual(800,player.Health); player.Recover(150); Assert.AreEqual(950,player.Health); } ... }关键写法拆解[Test]特性标记一个无参方法为测试用例Test Runner 会自动收集并执行它。方法名建议用Test前缀并描述意图如TestHealth。Arrange-Act-Assert 三阶段先构造Player并初始化血量Arrange调用被测方法Damage(200)、Recover(150)Act再用Assert.AreEqual(800, player.Health)校验期望值Assert。三段式让每个用例读起来像一份可读的需求说明书。断言方法Assert.AreEqual(期望值, 实际值)是 NUnit 最常用的断言Assert类还提供IsTrue、IsFalse、AreNotEqual、IsNull、ThrowsT等丰富断言。异常路径测试ExpectedException血量扣为负数时业务规则要求抛出NegativeHealthException。如何验证异常行为NUnit 提供了[ExpectedException]特性[Test] [ExpectedException(typeof(NegativeHealthException))] public void NegativeHealth() { Player player new Player(); player.Health 1000; player.Damage(500); player.Damage(600); }血量初始 1000第一次Damage(500)后剩 500第二次Damage(600)后血量为 -100触发正确实现中的抛异常逻辑。[ExpectedException(typeof(NegativeHealthException))]声明该测试只有抛出指定类型异常才算通过若方法正常返回或抛出其他异常测试失败。这样就把负数血量这一业务约束固化成了自动化回归项未来任何人改动Damage逻辑破坏该约束测试立刻变红。用错误的测试反向验证测试有效性测试本身也可能写错。示例工程贴心地提供了 PlayerTestWrong.cs用两段错误用例演示测试为什么会失败[Test] public void TestHealthWrong() { Player player new Player(); player.Health 1000.0f; player.DamageWrong(200); // 实际扣了 201血量变成 799 Assert.AreEqual(800,player.Health); // 断言 800 ! 799测试失败 player.DamageWrong(150); Assert.AreEqual(950,player.Health); } [Test] [ExpectedException(typeof (NegativeHealthException))] public void NegativeHealthNoException() { Player player new Player(); player.Health 1000; player.DamageNoException(500); // 不抛异常 player.DamageNoException(600); // 血量 -100仍不抛异常 }这两段用例的失败方式非常有教学价值错误用例失败原因体现的问题TestHealthWrongDamageWrong多扣 1 点血Assert.AreEqual(800, 799)不成立断言能敏锐捕捉差一错误off-by-oneNegativeHealthNoException声明期望抛异常但DamageNoException实际不抛测试验证的是行为契约违背契约即失败把它们与PlayerTest.cs对照恰好构成红/绿测试教学正确实现配正确断言 → 全绿错误实现配正确断言 → 全红。这也印证了单元测试的核心价值——测试必须能够失败否则没有意义。在编辑器中运行测试用 Unity示例为 5.5.0f3打开Unit4Unity/Editor Test Runner目录作为工程。打开菜单Window → Editor Tests Runner新版本为Window → General → Test Runner。测试窗口会列出编辑器模式下发现的所有[Test]方法点击Run All执行。预期结果PlayerTest的两个用例TestHealth、NegativeHealth通过PlayerTestWrong的两个用例失败失败信息会明确指出断言不符合或未抛异常。由于测试代码全部位于Editor目录且不依赖场景运行速度极快无需进入 Play Mode适合在每次逻辑改动后随手执行。把单元测试接入开发流程的实践建议结合示例工程可以总结出几条落地经验为纯逻辑层写测试优先测试血量、伤害公式、道具合成、背包容量等不依赖渲染和物理的 C# 类。Player就是教科书式例子——直接new出来即可测无需场景。用自定义异常表达业务约束NegativeHealthException把血量不能为负变成可测试、可传播的契约比默默让数值变负更安全。每个 bug 修复先补测试DamageWrong这类差一错误如果不写断言肉眼极难发现补上用例后回归成本趋近于零。保持测试独立与快速测试方法之间不要共享可变状态每个用例自行初始化示例中每次都new Player()并显式设置Health保证任意顺序、任意次数执行结果一致。测试代码随业务代码进版本库本仓库将测试与被测代码一同放在Assets/Editor下并纳入工程管理团队内所有人都能运行同一套用例。从仓库 README.md 可以看到单元测试的艺术Unit4Unity被列为该 Unity3DTraining 大杂烩仓库的独立专题模块与本工程配套的还有同目录下的目录索引Unit4Unity/README.md说明这套示例是作者系统性实践与沉淀的一部分可直接作为你项目中的测试范本。赞分享示例工程【免费下载链接】Unity3DTraining【Unity杂货铺】unity大杂烩~项目地址https://gitcode.com/gh_mirrors/un/Unity3DTraining点击查看免费下载相关推荐Unity3DTraining 之 Unit4Unity基于 Editor Test Runner 的 Unity 单元测试实战指南Unity3DTraining 之 Unit4Unity基于 Editor Test Runner 的 Unity 单元测试实战指南 导读 单元测试是保证游戏示例工程Ruby on Rails 单元测试实战使用 RSpec 为模型逻辑编写单元测试Ruby on Rails 单元测试实战使用 RSpec 为模型逻辑编写单元测试 本文围绕 unit_testing.md https://link.gitc文档教程教育4种数据可视化增强方案使用Magic CSS动画提升用户参与度4种数据可视化增强方案使用Magic CSS动画提升用户参与度 Magic CSS是一个专为CSS3动画设计的轻量级库提供超过70种特殊效果的动画实现压缩前端上一篇WechatExporter 微信聊天记录导出备份工具从 iTunes 备份到 HTML/PDF 导出的完整实战指南下一篇RealSense 深度相机点云生成实战从 10 行代码到多相机融合创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表