c# - 如何在 Unity Test Runner 中测试 Unity 协程

标签 c# unit-testing unity3d coroutine test-runner

我目前正在使用 Unity 2019 和 C# 开发一款游戏,我为此使用了很多事件和协程。协程是必需的,因为很多计算都是在其中完成的,我不希望游戏在那段时间卡住。现在,我开始使用测试运行器(播放模式)编写单元测试,协程未执行。因为我真的需要确保它们按预期工作,所以不可能只在“更高级别”上进行测试。

我已经尝试了正常的 StartCoroutine() 方法,它在测试文件中不起作用(“找不到方法名称”)。此外,我将我的一个协程重构为一个普通的 void 方法,一切正常,并通过了测试。我使用 Visual Studio 调试器查看它是否跳转到协程执行,但它没有。所以问题很明显,协程没有执行。我考虑过将计算逻辑移至另一个 void 函数并测试此函数(并省略协程),但我必须确保在协程中完成的迭代也能正常工作(它们通常比示例中的更复杂)。

这是一个显示一般结构的最小示例(通常会完成更多的计算)。

public class MeasuredValues
{
    List<Vector3> slidingWindow; // this is already filled when Normalize() is executed

    public IEnumerator Normalize()
    {
        //find coordinate system origin
        Vector3 originPosition = GetOrigin(); // returns a Vector3
        //normalization
        for (int i = 0; i < slidingWindow.Count; i++)
        {
            yield return null;
            //reset point to be at (0,y,0)
            slidingWindow[i] -= originPosition;
        }
    }
}

在我想要的测试文件中:

[Test]
public void TestNormalization()
{
    MeasuredValues myMeasuredValues = new MeasuredValues();
    // add many Vector3 to slidingWindow
    // call coroutine
    // assert, that the values are now as expected
}

我尝试了 myMeasuredValues.Normalize()(没用,调试器跳过了它)和 StartCoroutine(myMeasuredValues.Normalize)(没用, StartCoroutine 在该上下文中不可用)。 最后,我尝试了

    while (test.Normalize().MoveNext())
    {
        yield return null;
    }

但这永远不会结束,因为 MoveNext() 永远不会设置为 false。至少调试器跳进了协程方法。

是否有任何易于应用的解决方案来使用 Visual Studio 或 Unity Test Runner 测试我的协程而不需要重构整个项目结构?

最佳答案

I tried myMeasuredValues.Normalize() (didn't work, the debugger just jumped over it)

那当然是因为这不是你运行协程的方式

and StartCoroutine(myMeasuredValues.Normalize) (didn't work, the StartCoroutine is not available in that context).

那是由于 StartCoroutineMonoBehaviour 的成员。


您可以做的是引用场景中的任何 MonoBehaviour 并让这个处理例程。

例如,您可以有专门的类(class),例如

public class TestRoutineRunner : MonoBehaviour
{
    // implementation of the singleton pattern
    private static TestRoutineRunner instance;

    // Get the reference to instance or create it lazy when needed
    public static TestRoutineRunner Instance
    {
        get
        {
            // if instance already exists and is set return it right way
            if(instance) return instance;

            // otherwise find it in the scene
            instance = FindObjectOfType<TestRoutineRunner>();

            // if it is found in the scene return it now
            if(instance) return instance;

            // otherwise create a new one
            instance = new GameObject("TestRoutineRunner").AddComponent<TestRoutineRunner>();

            return instance;
        }
    }

    // Use this for adding a callback what should be done when the routine finishes
    public void TestRoutine(IEnumerator routine, Action whenDone)
    {
        StartCoroutine(RunRoutine(routine, whenDone));
    }

    private IEnumerator RunRoutine(IEnumerator routine, Action whenDone)
    {
        // runs the routine an wait until it is finished
        yield return routine;

        // execute the callback
        whenDone?.Invoke();
    }
}

然后在测试脚本中做

[Test]
public void TestNormalization()
{
    MeasuredValues myMeasuredValues = new MeasuredValues();

    ...

    // run the routine and pass the assert as callback
    TestRoutineRunner.Instance.TestRoutine(
        myMeasuredValues.Normalize(), 
        // for example as lambda expression
        () =>
        {
            // Assert here
        }
    );

    // or as method call
    TestRoutineRunner.Instance.TestRoutine(myMeasuredValues.Normalize(), AssertNow);
}

private void AssertNow()
{
    // assert here
}

关于c# - 如何在 Unity Test Runner 中测试 Unity 协程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58745946/

相关文章:

c# - 最后用缓动来回摇动一个物体?

c# - Unity 中音乐播放器的问题

c# - 将 Kinect 深度读数映射到 Unity

c# - 如果给定模式,是否有可以生成随机正则表达式字符串的类?

java - 使用 PowerMock 模拟单例的 getInstance

java - 如何对读取给定文件的方法进行单元测试

javascript - 如何安装 Jasmine : the javascript test tool on Velocity project

c# - 使用官方 C# 驱动程序更新 MongoDB 中的嵌入式文档

c# - 如何在 C++ 中声明类的静态实例?

c# - ASP.NET sass/scss 在运行时和编译时编译?