Unity单元测试要点介绍

本文介绍了在Unity中进行单元测试的重要性,特别是针对公共方法和属性、Observable以及积极和消极测试的选择。文章通过一个InventorySystem的案例,展示了如何利用Unity的内置测试工具UTF进行测试,以及如何通过依赖注入来解除脚本间的耦合。作者还讨论了EditMode测试的适用场景,并提供了一个InventorySystemTest的示例,验证了InventorySystem的正确性。

知识点涉及

文章主要涉及以下知识点:
  • 单元测试基本概念(必须)
  • Unity的内置测试工具Unity Test Framework(UTF)(必须)
  • 依赖注入概念(必须)
  • 面向数据设计,本文中使用的是UniRx框架(非必要) 

单元测试的必要性

  • 验证代码设计的正确性
  • 重构代码的安全网
  • 排除潜在的危险
  • 加深对代码理解
  • 代码审查的资料
  • 增加代码的茁壮性 我认为在Unity中,需要进行测试的点主要包括:

测试点选择

  • 公共方法
  • 公共属性
  • Hot Observable and cold Observable
  • 积极测试和消极测试
选择这些点的原因是:
  • 公共方法和属性访问性高;对公共方法的测试也隐式的对私有方法进行了测试
  • Observable相当C#中的Event,是游戏中各个组件、系统之间连接的纽带,必须测试
  • 积极的测试是希望得到一个True的结果,期望程序按照预期运行;消极的测试则是希望得到一个False结果,预见出错的条件,并设置适当的出错处理。

适合使用EditorMode进行测试的测试点

当测试点满足以下条件时,适合采用EditorMode进行测试:
  • 测试点不依赖于第三方脚本
  • 测试点具备量化指标。如果测试的点不具备量化指标,可能是因为方法太复杂了,可以尝试将大的方法拆分成单一的、较小的方法。

使用依赖注入破除依赖

如何编写在Unity中优秀的单元测试需要我们积累大量的经验和深入的思考,这里介绍一种比较棘手的情况: 对于脚本A方法的测试必须要依赖于脚本B,我们应该如何对脚本A进行测试。
我采取的策略是:将脚本A和脚本B的公共方法封装到脚本C的接口中,对脚本C的接口进行一系列的测试从而保证脚本A和脚本B的正确性。接下来我将以一个InventorySystem(背包系统)的设计进行阐述。
背包系统设计简述: InventorySystem由InventoryPresenter和InventoryGui组成。其中InventoryPresenter处理数据层的逻辑业务,InventoryGui则是将数据的变化映射到Scene中。IInventorySystem的具体实现交由 InventoryPresenter和InventoryGui,InventorySystem只是个适配器将这两个模块组合在一起。InventorySystem的代码见List1。  我的测试目的是想验证presenter和gui的方法是否按照我预想的进行运作。 List.1
public class InventorySystem : MonoBehaviour,IInventorySystem { InventoryPresenter presenter; InventoryGui gui; //implement interface ... public InventorySetting setting; public void Init() { presenter = new InventoryPresenter(this); gui = FindObjectOfType<InventoryGui>(); Assert.IsNotNull(gui, "Failed to find InventoryGui script in Hierarchy"); gui.InitModule(this); } private void OnEnable() { Init(); } }
在List.1中,InventorySystem主要由一下部分组成:
  • presenter处理数据逻辑,gui处理视图层逻辑。
  • 接口实现:接口方法和属性都只是presenter和gui方法和属性的包装。
  • Init方法:采用依赖注入方式实例化一个presenter,采用FindObject的方式激活gui,详细见InventorySystemWorkshop.scene。Init方法可以在单元测试中手动运行,自动产生presenter和gui方便之后的测试。
  • 在OnEnable中运行Init方法,完成系统初始化。

EditMode单元测试

在介绍测试脚本之前,我想先介绍下EditMode的运行特点:
  • 测试方法只运行一次 ,没有callback
  • 运行期间不会清空Hierarchy中的Game 这两个特性让我可以有效测试InventorySystem脚本在游戏场景中的表现。

InventorySystemTest介绍

在对InventorySystem进行测试时,只需对其接口进行测试,这样做有以下好处:
  • 公共方法测试起来访问性高,不需要诸如抽取重构等手段。
  • 公共方法肯定是调用过私有方法的,对公共方法的测试其实也隐式包含了对私有方法的测试。
  • 采用依赖注入设计的InventorySystem脚本是非常适合在EditMode下进行单元测试。
  • EditMode运行速度是远超过PlayMode,加快了测试进度。
下面结合部分InventorySystemTest代码进行要点说明,见List2。
public class InventorySystemTest { //初始化化InventorySystem private InventorySystem Config() { var inventory = GameObject.FindObjectOfType<InventorySystem>(); inventory.Init(); return inventory; } [Test] public void AddItem_true_5() { var inventory = Config(); inventory.AddItem("iron", 5); var hasIron = inventory.HasItem("iron"); var amount = inventory.GetAmount("iron"); Assert.IsTrue(hasIron); Assert.AreEqual(5, amount); } [Test] public void OnInventoryChanged_AddItem_receive5() { var inventory = Config(); inventory.OnInventoryChanged .Subscribe(x => { Assert.AreEqual(5, x.NewValue.Amount); Assert.AreEqual("copper", x.NewValue.Name); }); inventory.AddItem("copper", 5); } }
Config方法的职责是:获取Hierarchy中的InventorySystem的引用,并对其执行初始化操作(EditMode的特性2允许我这样操作)。 AddItem_true_5方法的测试目标:是向背包中添加5个iron,并查询,期望得到一个返回值5。 OnInventoryChanged_AddItem_receive5方法的测试目标是:是向背包中添加5个copper,欲检验OnInventoryChanged在AddItem事件发生时,是否推送了背包数据。预期是得到int 5和string “copper”。  经过测试,这两个方法通过了单元测试。所以我可以认为:这两个方法的实现是无误的。
考虑柔性负荷的综合能源系统低碳经济优化调度【考虑碳交易机制】(Matlab代码实现)内容概要:本文围绕“考虑柔性负荷的综合能源系统低碳经济优化调度”展开,重点研究在碳交易机制下如何实现综合能源系统的低碳化与经济性协同优化。通过构建包含风电、光伏、储能、柔性负荷等多种能源形式的系统模型,结合碳交易成本与能源调度成本,提出优化调度策略,以降低碳排放并提升系统运行经济性。文中采用Matlab进行仿真代码实现,验证了所提模型在平衡能源供需、平抑可再生能源波动、引导柔性负荷参与调度等方面的有效性,为低碳能源系统的设计与运行提供了技术支撑。; 适合人群:具备一定电力系统、能源系统背景,熟悉Matlab编程,从事能源优化、低碳调度、综合能源系统等相关领域研究的研究生、科研人员及工程技术人员。; 使用场景及目标:①研究碳交易机制对综合能源系统调度决策的影响;②实现柔性负荷在削峰填谷、促进可再生能源消纳中的作用;③掌握基于Matlab的能源系统建模与优化求解方法;④为实际综合能源项目提供低碳经济调度方案参考。; 阅读建议:建议读者结合Matlab代码深入理解模型构建与求解过程,重点关注目标函数设计、约束条件设置及碳交易成本的量化方式,可进一步扩展至多能互补、需求响应等场景进行二次开发与仿真验证。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值