【问题标题】:PlayMode Tests with Coroutine SetUp使用协程设置进行 PlayMode 测试
【发布时间】:2019-10-19 19:21:15
【问题描述】:

我是 Unity3D 测试的新手,我想为我们的游戏编写一些测试。我设法编写了这个工作很好的测试:

using System.Collections;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;
using Game.Characters;
using Game.Inventory;

namespace Tests
{
    public class ItemTests
    {
        [UnityTest]
        public IEnumerator ItemIsOnHand()
        {
            // Setup
            Player player = MonoBehaviour.Instantiate(Resources.Load<GameObject>("Tests/Player"));
            yield return null; // Wait for prefab to load
            Character character = player.GetComponent<Character>();
            WorldItem worldItem = WorldItem.Create(Resources.Load<Item>("Items/item"), 1);
            yield return null; // Wait for prefab to load
            character.Inventory.Give(worldItem);
            ItemScript itemScript = character.HandItemContainer.gameObject.GetComponentInChildren<ItemScript>();

            // Test
            Assert.IsNotNull(itemScript);

            // Teardown
            Object.Destroy(player);
            Object.Destroy(character);
            Object.Destroy(worldItem);
            Object.Destroy(itemScript);
        }

        [UnityTest]
        public IEnumerator ItemIsDisabledAtStart()
        {
            // Setup
            Player player = MonoBehaviour.Instantiate(Resources.Load<GameObject>("Tests/Player"));
            yield return null; // Wait for prefab to load
            Character character = player.GetComponent<Character>();
            WorldItem worldItem = WorldItem.Create(Resources.Load<Item>("Items/item"), 1);
            yield return null; // Wait for prefab to load
            character.Inventory.Give(worldItem);
            ItemScript itemScript = character.HandItemContainer.gameObject.GetComponentInChildren<ItemScript>();

            // Test
            Assert.IsFalse(itemScript.IsActive);

            // Teardown
            Object.Destroy(player);
            Object.Destroy(character);
            Object.Destroy(worldItem);
            Object.Destroy(itemScript); 
        }
    }
}

如您所见,两个测试(以及其他测试)都使用相同的设置和拆卸。我在方法之外声明变量(可用于每个测试)。 Teardown 方法运行良好,因为它不需要等待加载任何内容。

        private Player player;
        private Character character;
        private WorldItem worldItem;
        private ItemScript itemScript;

        [TearDown]
        public void Teardown()
        {
            Debug.Log("Teardown called");
            Object.Destroy(player);
            Object.Destroy(character);
            Object.Destroy(ectomodulatorWorldItem);
        }

但我无法使 SetUp 方法起作用。如果我将它设为协程 ([SetUp] public IEnumerator SetUp(){...}),它永远不会运行(我检查了调试器)。如果我使它成为一个简单的 void 方法并删除 yield return nulls,它会在 character.Inventory.Give(worldItem); 失败,因为 worldItem 仍然是 null

有什么方法可以使 SetUp 方法起作用吗?

谢谢

【问题讨论】:

  • 而不是yield return null 你试过yield return new WaitWhile (() -&gt; player == null) 吗?另外,您使用的是伪运行时测试吗?
  • @Draco18s yield return null 工作正常,但我可以尝试WaitWhile 方式。我不知道什么是伪运行时测试,抱歉。我正在使用 NUnit.Framework 并在 PlayMode 中运行测试。
  • and running tests in PlayMode 这就是我所说的“伪运行时”。通常单元测试是在播放模式之外完成的,但 Unity 的某些功能需要播放模式才能工作。
  • @Draco18s 我不确定两者之间有什么区别,以及我需要哪一个。在this question 中说需要 PlayMode 来测试物理,我将测试 Collider2D 检测,这就是为什么我认为 PlayMode 是合适的
  • 在这种情况下使用它是绝对正确的。只是还有一个非播放模式测试路径,而且速度更快,但是您几乎无法访问 UnityEngine 包中的任何内容(这就是为什么我问您是否使用播放模式路径,因为如果您没有't,你需要)。

标签: c# unit-testing unity3d nunit


【解决方案1】:

我找到了我需要的东西。就像[Test] 属性仅适用于void 方法并且您需要使用[UnityTest] 来运行协程一样,还有一个[UnitySetUp] 属性允许使用协程设置而不是void

更多信息的文档链接:https://docs.unity3d.com/Packages/com.unity.test-framework@1.1/manual/reference-actions-outside-tests.html#unitysetup-and-unityteardown

如果你有兴趣,我的测试文件是这样的:

using System.Collections;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;
using Game.Characters;
using Game.Inventory;

namespace Tests
{
    public class ItemTests
    {
        Player player;
        Character character;
        WorldItem worldItem;
        ItemScript itemScript;

        [UnitySetUp]
        public IEnumerator SetUp()
        {
            player = MonoBehaviour.Instantiate(Resources.Load<GameObject>("Tests/Player"));
            yield return null; // Wait for prefab to load
            character = player.GetComponent<Character>();
            worldItem = WorldItem.Create(Resources.Load<Item>("Items/item"), 1);
            yield return null; // Wait for prefab to load
            character.Inventory.Give(worldItem);
            itemScript = character.HandItemContainer.gameObject.GetComponentInChildren<ItemScript>();
        }

        [TearDown]
        public void Teardown()
        {
            Object.Destroy(player);
            Object.Destroy(character);
            Object.Destroy(ectomodulatorWorldItem);
        }

        [Test]
        public void ItemIsOnHand()
        {
            // Test
            Assert.IsNotNull(itemScript);
        }

        [Test]
        public void ItemIsDisabledAtStart()
        {
            // Test
            Assert.IsFalse(itemScript.IsActive);
        }
    }
}

【讨论】:

    猜你喜欢
    • 2020-04-24
    • 2019-11-28
    • 2018-05-13
    • 2020-05-07
    • 1970-01-01
    • 2019-12-17
    • 1970-01-01
    • 1970-01-01
    • 2022-12-14
    相关资源
    最近更新 更多