我目前正在使用 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).
那是由于 StartCoroutine
是 MonoBehaviour
的成员。
您可以做的是引用场景中的任何 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/