如何使用 Unity 测试框架为你的游戏运行自动化测试
如何使用 Unity 测试框架为你的游戏运行自动化测试
在游戏开发过程中,自动化测试是确保代码质量和游戏稳定性的关键环节。Unity测试框架(Unity Test Framework,UTF)为开发者提供了一套完整的测试解决方案,可以帮助开发者轻松地为游戏创建和运行自动化测试。本文将详细介绍如何使用Unity测试框架为游戏创建自动化测试,包括设置测试环境、创建测试脚本、编写测试用例以及在独立播放器中运行测试等内容。
构建设置窗口
你的第一个测试
你的第一个测试将涵盖从第三人称控制器包加载和移动主角的一些基础知识。首先使用一个简单的测试环境场景和一个要使用的角色预制资源来设置新项目。
打开名为Assets/StarterAssets/ThirdPersonController/Scenes/Playground.unity 的场景,并使用文件 > 另存为菜单将其副本保存到此新路径:Assets/Scenes/SimpleTesting.unity
如果你注意到游戏视图中的粉红色材质,请使用渲染管道转换器将材质从内置渲染管道升级到通用渲染管道 (URP)。请参阅本文以获得快速概览。
在项目资产文件夹中创建一个名为Resources 的新文件夹。注意:文件夹名称“Resources”在这里很重要,因为它允许使用 UnityResources.Load()方法。
将场景视图中的PlayerArmatureGameObject 拖放到新的 Resources 文件夹中,并在出现提示时选择创建Original Prefab。将预制资产重命名为Character。
这将是您今后测试中使用的基本角色预制件。从新的SimpleTesting场景中移除 PlayerArmature 游戏对象,并将更改保存到场景。
对于初始测试设置的最后一步,转到文件>构建设置,然后选择添加打开场景以将场景/SimpleTesting场景添加到构建设置中。
创建 C# 测试脚本
选择项目资产文件夹中的测试文件夹。右键单击并选择创建>测试>C# 测试脚本。
将新脚本命名为CharacterTests。在 IDE 中打开脚本进行仔细查看。初始类文件提供了两个方法存根,演示了一些测试基础知识。
接下来,您将确保测试加载“以测试为中心”的游戏场景。这应该是一个包含测试您关注的系统或组件所需的最低限度的内容的场景。
更新 CharacterTests 类以添加两个新的using语句,并实现InputTestFixture类:
using UnityEngine.InputSystem;
using UnityEngine.SceneManagement;
公共类 CharacterTests:InputTestFixture
在 CharacterTests 类的顶部添加两个私有字段:
GameObject 角色 = Resources.Load
键盘键盘;
角色字段将存储从资源文件夹加载的角色预制件的引用。键盘将保存对输入系统提供的键盘输入设备的引用。
通过在 CharacterTests 类中提供自己的方法,覆盖基础 InputTestFixture 类的 Setup() 方法:
公共覆盖无效设置()
{
SceneManager.LoadScene("Scenes/SimpleTesting");
base.Setup();
keyboard = InputSystem.AddDevice
var mouse = InputSystem.AddDevice
Press(mouse.rightButton);
Release(mouse.rightButton);;
}
Setup() 方法运行基类 Setup() 方法,然后通过加载测试场景和初始化键盘输入设备来设置您自己的 CharacterTests 类。添加鼠标输入纯粹是为了让第三人称控制器开始接收来自模拟/虚拟键盘设备的输入。这几乎就像一个“设置焦点”的动作。
对于您的第一个测试,您将从预制件中实例化角色并断言它不为空。将以下方法添加到您的测试类:
[测试]
public void TestPlayerInstantiation()
{
游戏对象 characterInstance = 游戏对象.Instantiate(character, Vector3.zero, Quaternion.identity);
Assert.That(characterInstance, !Is.Null);
}
当您在那里时,您可能想要清理示例模板测试方法。删除CharacterTestsSimplePasses和CharacterTestsWithEnumeratorPasses方法。
绿色复选标记表示测试已成功通过
通过第一个测试
保存脚本并返回编辑器中的测试运行器窗口。突出显示TestPlayerInstantiation测试并单击Run Selected。
绿色复选标记表示测试通过。您已断言该角色可以从资源中加载、实例化到测试场景中,并且此时不为空。您可能已经注意到,此测试使用的是[Test]注释,而不是[UnityTest]注释。UnityTest 属性允许协同程序在多个帧上运行测试。在这种情况下,您只需实例化角色并断言它已被加载。一般来说,您应该在编辑模式下使用 NUnit Test 属性而不是 UnityTest 属性,除非您需要产生特殊指令、需要跳过一帧或在播放模式下等待一定时间。
在播放模式下测试角色移动
角色运动测试
接下来,您将使用 UnityTest,因为您断言按住前进控制器键会使角色前进。
将下面提供的新测试方法添加到您的 CharacterTests 类。出现了两种新的测试辅助方法;Press() 和 Release()。这些都是由InputTestFixture基类提供的,通过模拟 InputSystem 控制的按下和释放来帮助您。
TestPlayerMoves() 方法执行以下操作:
在位置处从角色预制件实例化角色实例(X:0,是:0,Z:0)
按住虚拟键盘上的向上箭头键 1 秒钟,然后松开
再等待 1 秒(让角色减速并停止移动)
断言角色已经移动到 Z 轴上大于 1.5 个单位的位置。
保存文件,返回测试运行器并运行新测试。
玩家健康脚本
测试跌落伤害
接下来,您将通过添加一个简单的 Player Health 组件来测试自定义的 Monobehaviour 脚本。
在Assets/StarterAssets/ThirdPersonController/Scripts下创建一个新脚本。将其命名为PlayerHealth。
在 IDE 中打开脚本并用下面提供的代码替换内容。这里添加了很多新代码。总结一下,这个脚本会判断玩家角色是否处于坠落状态。如果在坠落状态下撞击地面一次,那么角色的生命值就会减少10%。
在Assets/Resources下找到 Character Prefab。打开预制件并添加新的 PlayerHealth 脚本组件。
接下来,您将使用测试场景来断言玩家从壁架上掉下来后其健康状况会下降。
使用 [UnityTest] 属性,您可以编写一个用于测试跌落伤害的播放模式测试。当掉落超过 0.2 秒时,玩家应该受到 0.1f 伤害(相当于最大生命值的 10%)。
在SimpleTesting场景中,您将看到通向壁架的楼梯。这是一个测试平台,用于在其上生成角色并测试PlayerHealth脚本。
再次打开CharacterTests.cs并添加一个名为 TestPlayerFallDamage 的新测试方法:
[UnityTest]
公共 IEnumerator TestPlayerFallDamage()
{
// 在测试场景中足够高的区域生成角色
游戏对象 characterInstance = 游戏对象.Instantiate(character, new Vector3(0f, 4f, 17.2f), Quaternion.identity);
// 获取对 PlayerHealth 组件的引用并断言当前处于完全健康状态 (1f)
var characterHealth = characterInstance.GetComponent
Assert.That(characterHealth.Health, Is.EqualTo(1f));
// 走下悬崖,等待坠落
Press(keyboard.upArrowKey);
产生返回新的WaitForSeconds(0.5f);
Release(keyboard.upArrowKey);
产生返回新的WaitForSeconds(2f);
// 断言由于跌落伤害而损失了 1 点生命值
Assert.That(characterHealth.Health, Is.EqualTo(0.9f));
}
您还需要在类文件的最顶部添加对 StarterAssets 命名空间的使用引用:
使用 StarterAssets;
上述测试遵循测试中常见的典型安排、操作、断言(AAA)模式:
- 单元测试方法的Arrange部分初始化对象并设置传递给被测方法的数据的值。
- Act部分使用安排好的参数调用被测试的方法。在这种情况下,当玩家跌落到地面时,调用被测方法由物理交互来处理。
- Assert部分验证被测方法的操作是否按预期运行。
确保角色在游戏中按预期倒下(包括造成正确数量的伤害)的测试
运行新测试
返回编辑器,运行新的测试。在播放模式下,您将看到角色走下边缘、跌倒(超过 0.2 秒的阈值才可归类为跌倒)并在撞击地面后受到伤害。
测试不仅可以用于测试代码更改不会破坏功能,还可以作为文档或指针,帮助开发人员在调整设置时考虑游戏的其他方面。
如何切换测试以在独立播放器版本中运行
在独立播放器中运行测试
如前所述,在测试运行器中运行播放模式测试默认使用 Unity 编辑器在播放模式下运行它们。您也可以将它们更改为在独立播放器下运行。
使用测试运行器窗口中的运行位置下拉菜单选择切换测试以在独立播放器版本中运行。
自动化和 CI
一旦您开始构建一套测试,下一步就是在构建完成后自动运行它们。构建后运行的自动化单元和集成测试有助于尽早捕获回归或错误。它们还可以作为云中远程自动构建系统的一部分运行。
拆分构建和运行
通常,您需要以自定义格式捕获测试运行结果,以便与更广泛的受众共享结果。为了在 Unity 编辑器之外捕获测试结果,您需要分离构建和运行过程。
在您的测试项目文件夹中创建一个名为SetupPlaymodeTestPlayer的新脚本。
SetupPlaymodeTestPlayer 类将实现 ITestPlayerBuildModifier 接口。您将使用它来覆盖并“挂钩”到ModifyOptions 方法,该方法接收构建的播放器选项,并允许您修改它们。
使用System.IO;
using UnityEditor;
using UnityEditor.TestTools;
公共类SetupPlaymodeTestPlayer:ITestPlayerBuildModifier
{
公共 BuildPlayerOptions 修改选项(BuildPlayerOptions playerOptions)
{
playerOptions.options &= ~(BuildOptions.AutoRunPlayer | BuildOptions.ConnectToHost);
var buildLocation = Path.GetFullPath("TestPlayers");
var fileName = Path.GetFileName(playerOptions.locationPathName);
如果 (!string.IsNullOrEmpty(fileName))
buildLocation = Path.Combine(buildLocation, fileName);
playerOptions.locationPathName = buildLocation;
返回玩家选项;
}
}
当在播放模式下运行测试时,此自定义 Player Build 修改器脚本执行以下操作(运行位置:在播放器上):
禁用内置播放器的自动运行并跳过尝试连接到正在运行的主机的播放器选项
将构建路径位置更改为项目内的专用路径(TestPlayers)
完成后,您现在可以预期构建完成后将位于TestPlayers文件夹中。这现在完成了构建修改并切断了构建和运行之间的链接。
接下来,您将实施结果报告。这将允许您将测试结果写入自定义位置,以备自动生成和发布报告。
在您的测试项目文件夹中创建一个名为ResultSerializer(如下所示)的新脚本。该类将使用对 TestRunCallback 的程序集引用并实现 ITestRunCallback 接口。
ITestRunCallback 的实现包含一个自定义的 RunFinished 方法,该方法设置播放器构建并进行测试,以将测试结果写入名为testresults.xml的 XML 文件。
结果输出可以在位于平台的 Application.persistentDataPath 位置的 testresults.xml 文件中找到
拆分构建和运行后运行测试
通过结合SetupPlaymodeTestPlayer.cs和ResultSerializer.cs,构建和运行过程现在被分开。运行测试将会把结果输出到位于播放器平台的 Application.persistentDataPath位置的testresults.xml中。
要使用这些钩子类中的某些类型,您需要添加对Tests.asmdef的额外引用。更新它以添加 UnityEditor.UI.EditorTests 程序集定义引用。
在播放器中运行测试现在将在TestPlayers文件夹中的项目下产生播放器构建输出,并在 Application.persistentDataPath 位置产生 testresults.xml 文件。
有关 Unity 测试的更多资源
Unity 测试框架课程
测试框架包中包含一个测试课程,其中包含示例练习,可帮助您了解有关使用 Unity 进行测试的更多信息。请务必使用包管理器获取课程的项目文件。
使用包管理器>软件包:Unity 注册中心>测试框架,找到示例下拉列表并导入课程练习。
练习将被导入到您的项目中并位于Assets/Samples/Test Framework下。每个示例都包含一个供您使用的练习文件夹,以及一个可供您在练习过程中与自己的工作进行比较的解决方案。
使用 UTF 对您的代码进行 QA
这次Unite Copenhagen 讨论对 UTF 进行了更详细的介绍,并提供了一些其他有趣的测试定制用例。请务必检查一下,看看还有什么可能。
Unity中的调试
阅读以下文章来加速 Unity 中的调试工作流程:
- 微软 Visual Studio 2022
- Microsoft Visual Studio Code
高级技术电子书
Unity提供了许多高级指南来帮助专业开发人员优化游戏代码。创建 C# 样式指南:编写更简洁、可扩展的代码汇集行业专家关于如何创建代码样式指南的建议,以帮助您的团队开发干净、可读且可扩展的代码库。
另一个受我们用户欢迎的指南是《70多条关于如何提高 Unity 生产力的技巧》。它包含了许多节省时间的技巧,可帮助您通过 Unity 2020 LTS 改善日常工作流程,其中包括经验丰富的开发人员可能会错过的技巧。
文档
进一步探索最新的 TestRunner API,了解其他 UTF 自定义属性,并通过 UTF文档发现更多生命周期。
在Unity 最佳实践中心查找 Unity 的所有高级电子书和文章。