Ogg*_*las 5 .net c# xunit asp.net-core-6.0 .net-6.0
在 .NET Core 3.1 和 .NET 5 中,我们进行了Xunit如下例所示的测试。它确保每个人Controller都有一个AuthorizeAttribute防止安全漏洞的方法。
将我们的 Web 项目升级到 ASP.NET Core 6 的最小托管模型时,不再需要Program和类。Startup一切正常,除了以下几点:
var types = typeof(Startup).Assembly.GetTypes();
Run Code Online (Sandbox Code Playgroud)
查看命名空间Example.Web,我也看不到任何可以从中加载程序集的类。如何Program.cs在 .NET 6 中加载程序集?
.NET 5 的示例:
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using Xunit;
namespace Example.Web.Tests.ControllerTests
{
public class AuthorizeAttributeTest
{
[Fact]
public void ApiAndMVCControllersShouldHaveAuthorizeAttribute()
{
var controllers = GetChildTypes<ControllerBase>();
foreach (var controller in controllers)
{
var attribute = Attribute.GetCustomAttribute(controller, typeof(Microsoft.AspNetCore.Authorization.AuthorizeAttribute), true) as Microsoft.AspNetCore.Authorization.AuthorizeAttribute;
Assert.NotNull(attribute);
}
}
private static IEnumerable<Type> GetChildTypes<T>()
{
var types = typeof(Startup).Assembly.GetTypes();
return types.Where(t => t.IsSubclassOf(typeof(T)) && !t.IsAbstract);
}
}
}
Run Code Online (Sandbox Code Playgroud)
Jer*_*ney 13
简单的答案是,您可以引用应用程序中的任何(可访问的)类,以获得对程序集的引用。它不必是ProgramorStartup类,也不必位于根命名空间中。
显然,您会希望选择一个您希望持久存在的类,并且不会在以后的版本中被重命名或删除。从历史上看,这个Startup班级符合这个标准。然而,对于 ASP.NET Core 6 最小托管模型,这显然不再是事实。
鉴于此,您可以在此处采取两种方法。
\nAssembly参考锚定在应用程序类上第一个选项是锚定public应用程序中的任意任意类。例如,您可以使用您的控制器之一。只要它被编译到相同的程序集中,Assembly.GetTypes()调用就会产生相同的结果。这可能看起来像:
using Example.Web.Controllers;\n\nvar types = typeof(ExampleController).Assembly.GetTypes();\nRun Code Online (Sandbox Code Playgroud)\n这种方法的主要缺点是该类完全是任意的,并且将来可能会被移动或重命名。当然,如果确实发生了这种情况,您可能无论如何都需要更新单元测试,所以这没什么大不了的。
\nProgram类公开给您的测试程序集另一种选择是将您的Assembly引用锚定于从您的文件编译的类中Program.cs,这与您之前的方法非常相似。这需要了解一些关于编译器如何处理该文件的信息。
当您使用 ASP.NET Core 6 最小托管模型时,您实际上是在利用 C# 9 的顶级语句。编译器会自动将任何顶级语句放入名为 的类中Program,而无需命名空间。
\n\n注意:这恰好与您对 的使用一致
\nProgram.cs,但这完全是偶然的;您可以重命名Program.cs为MyWebApplication.cs,但该类仍将被命名为Program。
问题是此类 Program 被标记为 internal,因此您的单元测试程序集无法访问该类。
不过,您可以通过将 ASP.NET Core 程序集的内部标记为对单元测试程序集可见来解决此问题。这可以通过将以下内容添加到例如您的AssemblyInfo.cs:
[assembly: InternalsVisibleTo("Example.Web.Tests")]\nRun Code Online (Sandbox Code Playgroud)\n或者,正如@kal在评论中指出的那样,通过在csproj文件中设置以下内容:
<ItemGroup>\n <InternalsVisibleTo Include="Example.Web.Tests" />\n</ItemGroup>\nRun Code Online (Sandbox Code Playgroud)\n完成此操作后,您可以Program使用以下方式访问您的课程:
var types = typeof(Program).Assembly.GetTypes();\nRun Code Online (Sandbox Code Playgroud)\n我不太喜欢以这种方式暴露程序集的内部结构,但这是单元测试中相当常见的做法,因此我将其作为一个选项包含在内,以防您已经这样做了。
\n最终,这实际上与第一个选项\xe2\x80\x94没有任何不同,您仍然将Assembly参考锚定在不同的类\xe2\x80\x94上,但它的优点是锚定到我们知道的类将始终存在,而不是某个任意的、特定于应用程序的类。阅读代码时这也可能感觉更直观。