上次更新时间:2019 年 12 月(阅读时长:6 分钟)

使用 Unity 测试框架测试游戏代码

本页内容简介:有关如何使用 Unity 测试框架 (UTF) 对项目进行 QA 的提示。UTF 是保证质量的最重要的工具之一;它用于在编辑器和支持的平台上运行自动化测试,而且,所有 Unity 用户都可以使用它!

对于您的大多数测试需求,新的 Test Runner API 为 UTF 带来了更高的灵活性和可扩展性。该工具通过 Unity Package Manager 提供,以便我们可以更快地提供错误修复和更新内容。这也意味着您可以在本地访问 UTF 的源代码。您可以查看、在调试时单步运行和修改该源代码。

要了解详细信息,请观看 Unity 工具和测试开发者 Richard Fine 和 Christian Warnecke 在 Unite Copenhagen 上的 UTF 主题演讲

使用 Unity 测试框架测试游戏代码

开始使用 Unity 测试框架

如果您不熟悉 Unity 测试框架 (UTF),请阅读简介文档。简而言之,UTF 让 Unity 用户能够在“编辑模式”和“播放模式”以及目标平台(例如独立平台、Android、iOS 等)上测试其代码。

UTF 使用 Unity 集成的 NUnit 库,这是一个用于 .Net 语言的开源单元测试库。有关 NUnit 的详细信息,请访问 NUnit 官方网站GitHub 上的 NUnit 文档

以下博客文章对于新用户很有帮助:

Unity 中的性能基准测试:如何开始

使用 Unity Test Runner 测试“测试驱动开发”

Test Runner API 概述

您可以通过 Test Runner API(请参阅下面的 API)从任何脚本以编程方式运行测试。它允许您检索将在“编辑模式”、“播放模式”或同时在这两种模式下运行的测试的列表(不运行它们)。您可以在每个测试的开始和结束、测试周期(即整个测试程序集)中的每个级别、每个单独的测试固定例程以及每个测试类和测试上挂接一些注册/取消注册回调。

在每个测试开始时,您将获得有关将要运行的测试路线的信息。测试完成后,您将看到测试结果。

除了在 Unity Editor 中以“播放模式”运行 UTF 之外,还可以使用新的自定义点在目标设备上运行它。这是在构建 Player 之前调用的;您可以修改 Player 构建选项,例如,更改测试运行设置和指定构建位置。

TestRunnerAPI.cs (C#)
void Execute(ExecutionSettings executionSettings);
void RegisterCallbacks<T>(T testCallbacks, int priority = 0) where T : ICallbacks;
void UnregisterCallbacks<T>(T testCallbacks) where T : ICallbacks;
void RetrieveTestList(TestMode testMode, Action<ITestAdaptor> callback);

拆分构建和运行

如果您要在未连接到本地计算机的目标设备上运行测试,例如,目标设备位于云中(或是云中的多个设备),则拆分构建和运行过程会很有用。

为此,您首先需要自定义测试 Player 构建过程本身。方法如下:

  • 禁用自动运行功能,以便在您构建 Player 之后,它不会启动并运行测试。
  • 将其保存到已知位置,而不是保存到系统的临时文件夹(默认将保存到该位置)。

然后,您在 Player 侧添加自定义结果报告(使用回调接口)以捕获所有结果,并将它们保存为 XML 文件或适合您的项目的任何格式。

请查看以下代码示例,以了解如何拆分构建和运行。在 Unite 主题演讲中,Richard Fine 逐步介绍了该应用程序的构建和结果报告这两部分的代码(6:28 处)。

拆分构建和运行:构建

构建:

 

SplitBuildAndRun:build.cs (C#)
[assembly:TestPlayerBuildModifier(typeof(SetupPlaymodeTestPlayer))]
public class SetupPlaymodeTestPlayer : ITestPlayerBuildModifier {
   public BuildPlayerOptions ModifyOptions(BuildPlayerOptions playerOptions) {
   	playerOptions.options &= ~(BuildOptions.AutoRunPlayer | BuildOptions.ConnectToHost);
   	var buildLocation = Path.GetFullPath("TestPlayers");
   	var fileName = Path.GetFileName(playerOptions.locationPathName);
   	if (!string.IsNullOrEmpty(fileName))
       	buildLocation = Path.Combine(buildLocation, fileName);
   	playerOptions.locationPathName = buildLocation;
   	return playerOptions;
   }
}

拆分构建和运行:在运行中保存结果

运行:

SplitBuildAndRun:SaveResults.cs (C#)
[assembly:TestRunCallback(typeof(ResultSerializer))]
public class ResultSerializer : ITestRunCallback {
   public void RunStarted(ITest testsToRun) { }
   public void TestStarted(ITest test) { }
   public void TestFinished(ITestResult result) { }
   public void RunFinished(ITestResult testResults) {     
   	var path = Path.Combine(Application.persistentDataPath, "testresults.xml");
   	using (var xw = XmlWriter.Create(path, new XmlWriterSettings{Indent = true}))
       	testResults.ToXml(true).WriteTo(xw);
   	System.Console.WriteLine($"***\n\nTEST RESULTS WRITTEN TO\n\n\t{path}\n\n***");
   	Application.Quit(testResults.FailCount > 0 ? 1 : 0);
   }
}

从菜单项启动特定的测试

通常,当开发者编写验证时,结果将显示在控制台窗口中,由于此处包含源源不断的消息,很容易令开发者迷失。如果您可以在编辑器中专用位置的测试套件中获得具有明确指示符的验证结果,会怎么样?这可以通过启动菜单项指示的特定测试来实现。

首先,您需要编写连接到 MenuItem 的方法,这与实现任何其他编辑器扩展菜单项的方式完全相同。然后,该方法创建一个 ScriptableObject 回调对象。您将使用 ScriptableObject 而不是常规类,以便测试可以进行一些操作,例如导致域重新加载,同时保持回调完整。启用 ScriptableObject 时,将为回调注册该对象,而禁用 ScriptableObject 时,则将其取消注册。

然后,设置筛选条件。通常,在启动 MenuItem 的测试时,需要运行特定类别或组的测试。使用筛选条件,您可以异步执行测试运行。它将运行数帧,以便您可以让 UnityTest、UnitySetUp 和 UnityTearDown 在测试期间记录引擎循环。当测试完成并注册 RunFinished 时,您可以将其设置为显示消息或打开结果窗口等任何对您的工作流程有意义的操作。

请参阅下面的代码示例。Richard 在 Unite 主题演讲中介绍了该应用程序的代码设置(11:50 处)。 

LaunchTestsFromMenuItem.cs (C#)
public class RunTestsFromMenu : ScriptableObject, ICallbacks {
   [MenuItem(“Tools/Run useful tests”)] public static void DoRunTests() {
   	CreateInstance<RunTestsFromMenu>().StartTestRun();
   }
   private void StartTestRun() {
   	hideFlags = HideFlags.HideAndDontSave;
   	CreateInstance<TestRunnerApi>().Execute(new ExecutionSettings {
       	filters = new [] { new Filter{ categoryNames = new[] { “UsefulTests” }}}
   	});
   }
   public void OnEnable() { CreateInstance<TestRunnerApi>().RegisterCallbacks(this); }
   public void OnDisable() { CreateInstance<TestRunnerApi>().UnregisterCallbacks(this); }
   /* ...RunStarted, TestStarted, TestFinished... */
   public void RunFinished(ITestResultAdaptor result) {       
   	…
   	DestroyImmediate(this);
   }

在构建前运行测试

在构建前运行测试可能会很棘手,因为构建过程需要从回调运行测试,因此没有机会启动引擎更新循环。但这样做的好处是,您可以在花时间进行实际构建(对于某些项目,这可能要花很长时间)之前检查基本功能是否正常运行。

您可以使用 IPreprocessBuildWithReport 接口来实现该应用程序,就像您实现任何其他类型的构建预处理一样。要获得结果,请像往常一样注册回调。

由于无法在构建过程中进入“播放模式”,因此可以使用 Test Runner API 在“编辑模式”下运行特定的测试。您可以通过按类别(例如,预构建验证测试类别)筛选来选择测试。您可以同步运行这些测试。

测试完成后,检查结果。如果出现任何问题,您可以抛出 BuildFailed 异常,这将导致构建过程中止。

该应用程序可以分为两部分 - ResultCollector 和预处理器 - Richard 在他们的演讲中详细介绍了这些内容(15:20 处)。

观看 Christian 和 Richard 的 Test Runner API 现场演示。请观看整个演讲,以获取更多 QA 提示!

RunTestsBeforeBuild.cs (C#)
   public ITestResultAdaptor Result { get; private set; }     
   public void RunStarted(ITestAdaptor testsToRun) { }
   public void TestStarted(ITestAdaptor test) { }
   public void TestFinished(ITestResultAdaptor result) { }
   public void RunFinished(ITestResultAdaptor result)
   {
   	Result = result;
   }
}

您喜欢本文吗?

是的。
还行。

我们使用 Cookie 来确保为您提供网站的最佳体验。有关更多信息,请访问我们的 Cookie 政策页面

明白了