如何在Unity中设置单元测试并修复缺少汇编引用错误?

63

我创建了以下结构:

├── Assets
├── Scenes
├── Scripts
│   └── MyExample.cs
├── Tests
│   ├── MyExampleTest.cs
│   └── Tests.asmdef

现在,当我在Unity中点击“运行全部”时,在测试运行器窗口中出现以下错误:

The type or namespace name `MyExample' could not be found. Are you missing an assembly reference?

我在Visual Studio中有两个项目:

  • Assembly-CSharp(包含src)

  • Tests(包含Tests)

我将Assembly-CSharp添加为第二个项目的引用。Visual Studio能够无错误地构建解决方案。

有人知道如何为Unity项目正确设置单元测试回归吗?

这是Tests.asmdef。

{
    "name": "Tests",
    "optionalUnityReferences": [
        "TestAssemblies"
    ]
}

我的示例测试.cs

using UnityEngine;
using UnityEngine.TestTools;
using NUnit.Framework;
using System.Collections;
using abc;

public class MyExampleTest{

    [Test]
    public void NewTestScriptSimplePasses() {
        // Use the Assert class to test conditions.
    }

    [UnityTest]
    public IEnumerator NewTestScriptWithEnumeratorPasses() {
        abc.Example m;
        Assert.That(false);
        yield return null;
    }
}

我的示例.cs

namespace abc
{
    public class Example
    {


    }
}

你正在使用哪个版本的Unity?以防万一,你的Tests.asmdef文件是否引用了仅编辑器才可以使用的测试程序集?否则,请注意,Unity的单元测试需要在一个Editor文件夹中。 - sonnyb
@sonny 我更新了问题,加入了 Tests.asmdef 文件。Unity 版本为 2018.1.0f2。 - HAL9000
看起来在Visual Studio中添加引用对Unity无效。当我关闭并重新打开时,引用不再设置。 - HAL9000
4个回答

64
尝试使用内置的测试运行器UI来设置您的测试装配文件夹和第一个测试脚本。
使用Window ->测试运行器 ->编辑模式 ->"创建测试组件文件夹",一旦您导航到新的测试组件文件夹,请使用在当前文件夹中创建测试脚本按钮。
特别是,与默认设置(在Unity 2018.1中)相比,您的Tests.asmdef 缺少 "Editor" include。
{
    "name": "Tests",
    "optionalUnityReferences": [
        "TestAssemblies"
    ],
    "includePlatforms": [
        "Editor"
    ]
}

为了设置测试,您不应该在Visual Studio项目中手动执行任何操作。

请注意,当我的程序集文件设置为“任意平台”时(如您的问题中所示):

{
    "name": "Tests",
    "optionalUnityReferences": [
        "TestAssemblies"
    ]
}

我的测试在测试运行器窗口中没有显示出来。

当我的程序集文件明确设置为仅包括“Editor”平台时(如前面的示例所示),我的测试在测试运行器窗口中正确显示。

(这种行为对我来说有点违反直觉。)


您还需要为脚本设置汇编定义。在您的Scripts文件夹下,创建一个汇编定义文件MyScriptAssembly.asmdef(使用Unity菜单Assets -> Create -> Assembly Definition或手动创建):

{
    "name": "MyScriptAssembly"
}

然后,确保你的Tests.asmdef引用了你的脚本程序集:

{
    "name": "Tests",
    "references": [
        "MyScriptAssembly"
    ],
    "optionalUnityReferences": [
        "TestAssemblies"
    ],
    "includePlatforms": [
        "Editor"
    ],
    "excludePlatforms": [],
    "allowUnsafeCode": false
}

您还可以在Unity编辑器的检查器窗口中设置此项。选择.asmdef文件时,在检查器中查看“引用”:

assembly definition inspector window

(更多细节请参见Unity关于程序集定义文件的文档

也许这与您的 MyExample.cs 和 MyExampleTest.cs 有关。您能否更新您的问题并附上这些文件的代码? - sonnyb
@HAL9000 我已经更新了我的答案。我对Unity中的新汇编定义功能不是很熟悉,但希望这可以解决你的问题。 - sonnyb
2
我之前遇到了一些奇怪的错误。我按照你的建议重新创建了这个项目,最终它终于能运行了。非常感谢你 :) 问题是由于缺少程序集定义导致的。 - HAL9000
3
谢谢您的精彩回答! - rennat
1
在我的脚本文件夹中设置AssemblyDefinition似乎会破坏我的脚本(由于某些未知原因现在彼此找不到),并且在我单击“+”并滚动时,Test.asmdef -> Assembly References的检查器中也不会显示。 - Noah Ternullo
显示剩余4条评论

23

最终找到了正确的解决方案,而且一切都是通过编辑器完成的。

因此,我们的目标是让测试程序集引用真正的代码程序集。为了做到这一点,您需要定义这两个程序集,并在Unity中设置引用。

  1. 像往常一样在Unity中创建您的测试,生成程序集。
  2. 进入您的脚本文件夹(通常是Assets/Scripts),右键单击->创建程序集定义,这将在其中创建一个程序集文件。
  3. 在Unity中进入您的测试程序集信息,并添加引用到您的真实程序集,并确保它仅标记为Editor平台。

完成。您的测试应该在Unity中可见并可运行,并且可以引用任何其他脚本。


请注意,您可以安全地删除根文件夹中的所有.csproj和.sln文件,Unity将重新创建它们(它们也不应在源代码控制中)。

因此,进行此类更改的测试步骤应始终为:

  1. 删除文件夹中的任何Visual Studio相关文件。
  2. 选择 Assets->打开C#项目。 让它处理。
  3. 如果一切都编译和运行正常,您的测试也是如此,则已成功设置事项。

附赠:我们的项目中还有一些调试项目,它们位于Assets/DebugScenes/DebugScripts。通过为它们创建单独的程序集,并将其引用实际脚本程序集(如果需要),并标记为Editor平台,我们确保这些脚本不会在构建时自动包含在构建中。


额外阅读。您可能会认为您不想为所有脚本创建程序集,因为您只想测试其中一些。这是真的,您可以为子文件夹创建程序集,但这会让您陷入麻烦,因为您必须从一个实际脚本程序集引用到另一个。所以,请确保一切都整洁有序,有意义...


我们的测试和实际脚本程序集信息并排。游戏标题中有行星


1
当我将程序集定义添加到我的脚本中时,它会抱怨在当前上下文中不存在“OVRInput”(这是一个Occulus Rift类)。很难强制Unity添加对相关OVR dll的引用。 - Kamran Bigdely
在新的Unity(2019.1)中,程序集定义中有一个额外的标志,即“包含在默认程序集中”或类似的内容。由于它以前不存在,因此上面的图片中没有显示出来。尝试在您的OV程序集定义中启用它。 - Thanasis Kapelonis
1
如果您在Script文件夹中有Editor子文件夹,则似乎无法正常工作。我想我必须创建两个程序集定义,一个用于引擎,一个用于编辑器。但是更改所有层次结构非常痛苦,是否有任何解决方案? - Flavien Marianacci
1
如果我添加一个“程序集定义”,测试会找到我的脚本,但由于程序集新的引用错误,几乎每个脚本都无法正常工作(例如,“未找到类型或命名空间名称 'UnityEngine'(您是否缺少使用指令或程序集引用?)”)。我尝试了一些选项,如“自动引用”,但没有帮助。Unity 2020.3。 - tturbo
非常感谢您。但是,在具有多个模块和插件的大型项目中,这个工作流程非常困难。我们必须为每个部分设置AssemblyDefinition。如果没有自动引用,对于我们来说,放弃unity-testframework已经足够困难了。因此,我们创建了一个轻量级的替代方案。还有其他更好的想法吗? - user890054
可以在不创建程序集的情况下使用单元测试吗(只使用默认程序集)?即使创建一个单一程序集也会破坏我们的代码。 - undefined

15

轻量级、"零程序集"的替代安装方案:

Assets
├── Scenes
├── Scripts
│   └── MyGameScript.cs
├── Editor
│   └── MyGameScriptTests.cs

Editor目录中的所有脚本都可以引用NUnit.Framework命名空间,这些测试将显示在Test Runner窗口中。

它的主要优点是简单性。我确信它也有缺点,但对于日常项目来说,这是一种福音。零麻烦设置,只需工作即可。


4
哦,糟糕!是的,这非常好用。我的一个抱怨是似乎无法运行PlayMode测试,这是一个令人沮丧的缺点。 - Will Lacey
测试可能最终会与其他代码捆绑在最终构建中。 - Štefan Schindler
3
@ŠtefanSchindler 幸运的是,“Editor”目录中的脚本不会被编译。 - Andrew Łukasik
这个解决方案仍然存在一个主要问题,即我无法从MyGameScriptTest.cs引用MyGameScript.cs。Unity 2020.3。 - tturbo
1
@tturbo 使用Unity测试框架1.1.33,Unity编辑器2021.3.25f1或2022.3.7f1,我可以从Editor文件夹(或其子文件夹)中的脚本引用Scripts文件夹(或其子文件夹)中的脚本。 - Helder Daniel
1
可能是设置编辑器模式测试的最简单方法,谢谢。在我使用它的过程中,我没有发现任何缺点。 - Helder Daniel

0

Andrew Lukasik的回答可能是关于编辑器模式测试最简单的解决方案。它不需要程序集。

然而,我没有找到一种类似的方式来设置播放模式测试,而不需要程序集。

在这个答案中建议了一种为分布在多个文件夹中的脚本设置播放模式单元测试的简单方法:只需在Scripts文件夹的根目录下创建一个程序集定义

注意:类似的步骤也可以用于设置编辑器模式测试。
完整步骤如下:

  1. 测试运行器中创建一个用于测试的文件夹,例如:Assets/Test/PlayMode
    该文件夹中将创建一个程序集定义:PlayMode.asmdef

  2. 现在,在脚本文件夹的根目录中创建另一个程序集定义,例如:Assets/Script/scripts.asmdef,使用菜单选项:

资产 > 创建 > 程序集定义
3. 在播放模式测试文件夹中选择程序集定义 PlayMode.asmdef,然后在检查器中的程序集定义引用字段中添加脚本根程序集:scripts.asmdef

enter image description here

如果Unity编辑器出现错误,提示一个或多个命名空间缺失,例如:“新的输入系统”命名空间,请使用这个answer中的步骤:
  • 选择脚本文件夹根目录下的程序集定义,scripts.asmdef
  • 在检查器中的程序集定义引用字段中,添加缺失的命名空间,例如:Unity.InputSystem

enter image description here


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接