c# - 使用 CustomWebApplicationFactory 进行 Asp.Net 核心集成测试 - 它是如何工作的?
问题描述
我试图更好地理解集成测试。默认情况下,很多示例IClassFixture<T>
用于集成测试(例如https://docs.microsoft.com/en-us/aspnet/core/test/integration-tests?view=aspnetcore-2.2#basic-tests-with- -default-webapplicationfactory)。
这对于测试诸如页面加载、正在显示的表单、我是否获得正确的 http 状态代码等非常有用。但是在测试 API 时,您会希望存在一些种子数据。为了让种子数据进入您的测试,典型的首选是 EF 内存数据库。这是通过自定义 Web 应用程序工厂实现的,您可以在其中创建范围、请求适当的服务(即 dbcontext)并为其播种(例如https://docs.microsoft.com/en-us/aspnet/core/test /integration-tests?view=aspnetcore-2.2#customize-webapplicationfactory)。
我有一个正在运行且功能齐全的集成测试项目。但是它工作方式的细微差别仍然让我感到困惑。
假设当您创建CustomWebApplicationFactory时,我是否正确,本质上您是在创建自定义“Program.cs”(即应用程序的典型入口点),您可以根据需要在其中自由添加额外的测试服务/过滤器?
下面是我用于集成测试的自定义 Web 应用程序工厂。我的 API 对大多数端点都有基本的身份验证,所以我添加了一个全局过滤器来绕过它。但是我在下面所做的在我的实际 API 中的Program.cs中基本上是相同的(唯一的区别是我没有添加假用户和全局匿名过滤器)。所以我被引导相信我的上述观点是正确的。这是一个正确的假设吗?
我想验证的另一点是,在实际的单元测试中,我可以用模拟替换服务。这在集成测试中是否可行,我可以将 DI 实例换成请求的服务作为测试服务?
例如,我的应用程序有一项IUploadFileToAzure
服务。TestUploadFileToAzure
除了使用 UploadFileToAzure 作为 DI 实例,我可以在集成测试中用服务替换该实现吗?
多次注册服务需要最后一次注册服务,所以我想知道这是否可以用作我上述观点的解决方法。这甚至被推荐吗?我知道它违背了测试服务的目的,但想验证这是否可能。我尝试在本地对此进行测试,但没有成功。
public class CustomWebApplicationFactory<TStartup> : WebApplicationFactory<Startup>
{
protected override IWebHostBuilder CreateWebHostBuilder()
{
return WebHost
.CreateDefaultBuilder<Startup>(new string[0])
.ConfigureServices(services =>
{
services.AddSingleton<IStartupFilter, AddCustomMiddlewareStartupFilter>();
});
}
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder
.UseEnvironment("Development")
.ConfigureServices(services =>
{
services.AddMvc(opt =>
{
//add a global anonymous filter
opt.Filters.Add(new AllowAnonymousFilter());
//add a filter for adding a fake claimsprincipal so that the user service
//correctly identifies the user
opt.Filters.Add(new FakeClaimsPrincipalFilter(true, false));
});
services.AddEntityFrameworkInMemoryDatabase();
// Create a new service provider.
var provider = services
.AddEntityFrameworkInMemoryDatabase()
.BuildServiceProvider();
// Add a database context using an in-memory
// database for testing.
services.AddDbContext<AppDbContext>(options =>
{
options.UseInMemoryDatabase("TestDb");
options.UseInternalServiceProvider(provider);
});
// Build the service provider.
var sp = services.BuildServiceProvider();
// Create a scope to obtain a reference to the database context
using (var scope = sp.CreateScope())
{
var scopedServices = scope.ServiceProvider;
var apiDb = scopedServices.GetRequiredService<AppDbContext>();
// Ensure the database is created.
apiDb.Database.EnsureCreated();
}
});
}
}
解决方案
假设当您创建 CustomWebApplicationFactory 时,我是否正确,本质上您是在创建自定义“Program.cs”(即应用程序的典型入口点),您可以根据需要在其中自由添加额外的测试服务/过滤器?
是的你是对的。因为Program.cs
它将创建真正的主机服务器。对于CustomWebApplicationFactory
,它将TestServer
为集成测试创建。
我的应用程序有一个 IUploadFileToAzure 服务。我可以在集成测试中用 TestUploadFileToAzure 服务替换该实现,而不是使用 UploadFileToAzure 作为 DI 实例吗?
对于替换现有服务,您可以尝试ConfigureTestServices
并参考Inject mock services
推荐阅读
- android - how to get the deleted contact from the android phone and how to restore it
- node.js - NodeJs Mongodb:连接 ECONNREFUSED
:27017 - python - Plotly:如何使用 bx.bar 更改颜色条的标题?
- javascript - JavaScipt:将 HTML 实体作为函数参数传递
- python - 如何获取烧瓶中的最后一个条目
- python-3.x - 将带有参数的python函数应用于apache光束管道
- c# - 如何从管理端获取数据然后在客户端显示?
- python - 让 Python 与外部程序中的工具栏菜单和选项进行交互
- angular - 通过带角度的路线打开离子模态
- java - onClickListener 按钮在片段中不起作用