【问题标题】:Is there a way to unit test top-level statements in C#?有没有办法在 C# 中对顶级语句进行单元测试?
【发布时间】:2022-02-10 21:00:11
【问题描述】:

我一直在摆弄顶级语句作为简单控制台应用程序的入口点,因为新的 .NET 6 模板将它们用作默认值。

然而,正如language specification 非常清楚地指出的那样:

请注意,名称“Program”和“Main”仅用于说明目的,编译器使用的实际名称取决于实现并且类型和方法都不能通过源代码中的名称引用强>。

那么,如果我不能引用隐式的Program 类并且它是Main() 方法,是否可以编写单元测试来检查顶级语句本身的执行流程?如果有,怎么做?

【问题讨论】:

  • 真的需要这个吗?这可能只是一个研究问题吗?有点像“我可以让猪飞”之类的问题吗? (顺便说一句,猪的答案是肯定的,只是时间不长)
  • 一个问题:为什么真的有人想要这样做吗?任何复杂到足以保证单元测试的程序都没有(或:应该有)Main() 或顶层的任何主要功能。
  • @Lasse 实际上两者兼而有之。我认为对于新学习者来说使用控制台应用程序来提高他们的技能非常棒,如果他们碰巧正在学习单元测试,那么能够测试编译器生成的 Main() 方法的执行可能会有所帮助。但我不得不承认,想知道这是否可能的冲动主要是出于对顶级语句的局限性的好奇。
  • @Franz 我同意,但我仍然很想知道是否有办法。

标签: c# unit-testing testing .net-6.0 toplevel-statement


【解决方案1】:

是的。一种选择(从 .NET 6 开始)是使测试项目的内部结构对测试项目可见,例如通过向 csproj 添加下一个属性:

<ItemGroup>
  <InternalsVisibleTo Include ="YourTestProjectName"/>
</ItemGroup>

然后为顶级语句生成的Program 类应该对测试项目可见,您可以通过以下方式运行它:

var entryPoint = typeof(Program).Assembly.EntryPoint!;
entryPoint.Invoke(null, new object[] { Array.Empty<string>() }); 

这样的东西在内部用于以最小的托管模型对ASP.NET Core 6 执行集成测试。

请注意,如果您在顶级语句中使用await,则generated Main 方法可以返回任务,因此您可能需要捕获entryPoint.Invoke 的返回并测试它是否为Taskawait它。

另一种方法是将Program 类显式声明为部分(例如在顶级语句的末尾并在测试项目中使用它):

// ...
// your top-level statements

public partial class Program { }

【讨论】:

  • 感谢您的详细解答!
  • 虽然现在使用的是 Program 这个名称,但由于文档明确指出它依赖于实现,因此将来可能会中断。
  • @LasseV.Karlsen 是的,虽然微软推荐这种方法用于integration testing
  • 虽然有细微差别。如果您明确声明public partial class Program { },那么即使托管入口点的类型名称发生变化(根据文档,它可以),那么在同一个程序集中仍然会有一个Program 类,然后您可以使用它来获取 to 该程序集以获取它的入口点,无论它可能位于哪个类型。
  • @LasseV.Karlsen 这些是替代品。他们建议做一个或另一个。
猜你喜欢
  • 2010-11-13
  • 1970-01-01
  • 1970-01-01
  • 2011-03-23
  • 2017-03-11
  • 1970-01-01
  • 2017-06-17
  • 1970-01-01
  • 2021-08-23
相关资源
最近更新 更多