.NET 6(ASP.NET Core 6.0)从测试项目获取启动或程序集 [英] .NET 6 (ASP.NET Core 6.0) get Startup or Program Assembly from Test project
问题描述
在.NET Core 3.1和.NET 5中,我们有一个如下例所示的Xunit
测试。它确保每个Controller
都有一个AuthorizeAttribute
以防止安全泄漏。
Program
和Startup
类。除以下各项外,一切运行正常:
var types = typeof(Startup).Assembly.GetTypes();
查看命名空间Example.Web
,我也看不到要从中加载程序集的任何类。如何在.NET 6中加载Program.cs
程序集?
.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);
}
}
}
推荐答案
简单的答案是,您可以在应用程序中引用任何(可访问)类,以便获得对程序集的引用。它不必是Program
或Startup
类,也不必位于根命名空间中。
您显然希望选择一个期望持久的类,并且不会在以后的版本中被重命名或删除。从历史上看,Startup
类符合该标准。然而,对于ASP.NET Core 6最小托管模型,这显然不再是真的。
鉴于此,您可以在此处采用两种方法。
选项1:将Assembly
引用锚定在应用程序类之外
第一个选项是从应用程序中锚定任何任意的public
类。例如,您可以使用其中一个控制器。只要它被编译到相同的程序集中,Assembly.GetTypes()
调用将产生相同的结果。这可能类似于:
using Example.Web.Controllers;
var types = typeof(ExampleController).Assembly.GetTypes();
这种方法的主要缺点是类完全是任意的,将来可能会被移动或重命名。当然,如果确实发生了,您可能无论如何都需要更新您的单元测试,所以这不是什么大事。
选项2:向测试程序集公开Program
类
另一种选择是将Assembly
引用锚定在从Program.cs
文件编译的类之外,这与您之前的方法非常相似。这需要对编译器如何处理此文件有所了解。
当您使用ASP.NET Core 6最小托管模型时,您实际上是在利用C#9的顶级语句。编译器自动将任何顶级语句放入名为Program
且没有命名空间的类中。
注意:与您使用的
Program.cs
不谋而合,但这完全是偶然的;您可以将Program.cs
重命名为MyWebApplication.cs
,但类仍将命名为Program
。
问题是此Program
类被标记为internal
、,因此您的单元测试程序集无法访问。
AssemblyInfo.cs
来实现:
[assembly: InternalsVisibleTo("Example.Web.Tests")]
或者,如@kal在注释中指出的,在csproj
文件中设置以下内容:
<ItemGroup>
<InternalsVisibleTo Include="Example.Web.Tests" />
</ItemGroup>
完成后,您可以使用以下命令访问Program
类:
var types = typeof(Program).Assembly.GetTypes();
我不太喜欢以这种方式公开程序集的内部结构,但这是单元测试中相当常见的做法,因此我将其作为一个选项包括在内,以防您已经在这样做了。
最终,这与第一个选项没有什么不同-您仍然将Assembly
引用锚定在不同的类上-但它的优势是锚定到一个我们知道将始终存在的类,而不是某个任意的、特定于应用程序的类。在阅读代码时,这可能也会感觉更直观。
这篇关于.NET 6(ASP.NET Core 6.0)从测试项目获取启动或程序集的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!