【问题标题】:How to detect empty IEnumerator function calls during unit testing?如何在单元测试期间检测空的 IEnumerator 函数调用?
【发布时间】:2021-08-21 12:05:35
【问题描述】:

我正在使用 Unity 的运行模式测试单元,该单元在 Enumerator 函数(又名协程)上运行。

在测试内部,它们会调用更多的子例程,其中一些是普通函数,一些是IEnumerator函数,从而允许测试运行并跨越几帧。

[UnityTest]
public IEnumerator Test1( )
{
    SubAction1( );
    yield return SubAction2( );
}

void SubAction1( ) // A sub function that does not need to run over several frames
{ 
}

IEnumerator SubAction2( ) // A sub function that need to span over several frames
{
    ... // More code
    yield return WaitForSeconds( 1 );

    ... // More code
    while( condition == false )
        yield return null; // Wait until condition becomes true to continue

    ... // More code
}

如果我误用 SubAction2 并像普通函数一样调用它:

SubAction2( ); // without yield return, this is misuse

它仍然会编译并静默运行!这将使 SubAction2 不会执行其所有代码。这只是一个小错字,但这可能会导致整个测试静默失败! SubAction2 是一个 IEnumerator 函数,应该通过 yield return 调用。

我是否有某种方法来进行完整性检查,或者强制使用“yield return”调用此函数?

我正在寻找以下任何可能的解决方案:

  • 一些 C# 语言模式可防止在运行时或编译时发生此类误用。
  • 或者一些有助于检查这种滥用的神奇属性?
  • 或有助于检测此类误用的编辑器警告(例如 VisualStudio intellisense 中的选项?)

我现在的解决方案是使用“DoSubAction2”之类的前缀命名所有 IEnumerator 函数,然后进行正则表达式搜索以查找没有“yield return”的“Do”函数调用的出现,以手动检查是否存在误用。

【问题讨论】:

  • 对问题审阅者的评论:虽然问题本身与 GameDev SE 有一些关系,但它更侧重于 C# 语言方面,所以我会在这里问。
  • 顺便说一句,当您现在可以访问 async/await 时,真的没有理由在 Unity 中使用遗留协程。虽然前者在 .NET Framework 4.x+ 推出之前很流行,但当看到yield 的使用方式时,它往往会引起C# 开发人员的注意
  • 您使用的是什么 IDE? Rider 和 afaik 也 VisualStudio(但也许它只是 Resharper ^^)对此发出警告;)
  • @derHugo 我正在使用视觉工作室,但没有 resharper。嘿,很高兴知道它提供了这样的功能。我会记住这一点。但由于经济上的选择,我会先尝试寻找替代方案。
  • 严格来说,调用返回IEnumerator作为方法的方法并没有错。你现在有一个生成器而不是协程。您希望收到有关“未使用退货”的某种警告。

标签: c# unity3d enumerator


【解决方案1】:

鉴于您基本上是在编写测​​试时尝试指导自己,您可以选择一种情况,即您总是调用某个“帮助”方法,如果您错了,让编译器指导您。

一个选项是使用指定调用方法的方式的基类或实用程序。 然后,您可以创建具有重载、处理 IEnumerator 或常规方法的方法。

private void Test1()
{
    CallMethod(MethodNoParams);

    CallMethod(() => MethodOneParam(1));

    CallMethod(CoroutineMethod());

    CallMethod(MethodNoParams()); // Does not compile
    CallMethod(CoroutineMethod); // Does not compile
    CallMethod(MethodOneParam(1)); // Does not compile
}

private void MethodNoParams()
{

}

private void MethodOneParam(int something)
{

}

private System.Collections.IEnumerator CoroutineMethod()
{
    yield return new WaitForEndOfFrame();
}



// These methods in utility or base class
public void CallMethod(Action method)
{
    method.Invoke();
}


public void CallMethod(System.Collections.IEnumerator enumerator)
{
    StartCoroutine(enumerator);
}

【讨论】:

  • 我也想到了类似的东西,这种模式是可行的,但它会失去等待完成的功能,例如CoroutineMethod(line7)在继续MethodNoParams之前完成:)
【解决方案2】:

检查可用选项后,我决定使用 Visual Studio VSIX 扩展并编写一个 Roslyn 分析器。这种误用会在 IDE 中作为警告提示。

为了完整起见,我已将所有分析器/修复器代码上传到那里:Github

这些是我使用的指南:

其他相关的东西

  • 根据@derHugo 的说法。 Resharper(需要付费订阅)似乎也会警告这种模式。
  • 还有一个开源项目Roslynator2019,它捆绑了大量的代码分析器,专注于一般C#的代码设计,它是免费的。但遗憾的是它不包括我的情况。
  • 看起来 C# async-await 也可以与 Unity 单元测试一起使用。它只需要一些类似UniTask 提供的外壳。

我要感谢讨论中的每个人。对于读者,我希望你今天学到了一些新东西。

【讨论】:

  • 很高兴您找到了解决方案。您可能想查看静态代码分析和报告工具 nDepend。您可以通过 LINQ 语言使用自己的规则对其进行自定义,以在作者时以及夜间构建期间检查代码。 See also...
猜你喜欢
  • 2018-06-11
  • 1970-01-01
  • 2018-02-16
  • 2019-11-15
  • 2010-12-19
  • 2018-07-28
  • 1970-01-01
  • 2016-08-07
  • 1970-01-01
相关资源
最近更新 更多