如何使用 WebApplicationFactory 对 .NET 6 Web Api 项目进行集成测试?
Posted
技术标签:
【中文标题】如何使用 WebApplicationFactory 对 .NET 6 Web Api 项目进行集成测试?【英文标题】:How to do integration testing for .NET 6 Web Api projects using WebApplicationFactory? 【发布时间】:2021-08-30 16:01:57 【问题描述】:我一直在使用 WebApplicationFactory 在 .NET 5、.NET Core 3.1 和 .NET Core 2.1 中进行集成测试。对我来说一切正常。
我只是创建我的项目:
dotnet new webapi
然后我看到一个 Web api 项目有一个 Startup 类。
然后我创建一个工厂类的实例:
private readonly WebApplicationFactory<Startup> factory = new WebApplicationFactory<Startup>();
正如here 和here 所解释的那样。
WebApplicationFactory 类是我非常喜欢的。它使编写集成测试变得容易。我很喜欢。微软文档also refer to it for .NET 6。
但是,在使用 .NET 6 时,如何确保我的代码可以编译?
上述命令行语句:
dotnet new webapi
结果是一个运行良好的项目,但是(安装了 .NET 6 SDK 时)没有 Startup 类......现在我的测试无法编译,原因只有一个:Startup 类不存在。
如何解决这个问题?我很难想象我不能再编写集成测试了,因为WebApplicationFactory<Startup>
不再编译了。但现在,这是我需要面对的现实。我该如何解决这个问题?我期待能够使用WebApplicationFactory
类并继续编写集成测试。但是怎么做呢?
【问题讨论】:
【参考方案1】:.NET 6 RC1 中添加了对此的支持。这是生产中支持的第一个版本。
您可以传递Program
而不是Startup
。 Startup
现在基本上合并到 Program
中。 Program
类是从 Program.cs
文件中的***语句自动生成的。不过它不是公共类,因此您需要将InternalsVisibleTo
添加到应用程序的项目文件中,以使其对测试项目可见。
<ItemGroup>
<InternalsVisibleTo Include="MinimalApiPlayground.Tests" />
</ItemGroup>
在this example Damien Edwards 定义了一个WebApplicationFactory<Program>
来演示测试 Todo 最小 API。
创建测试应用与使用 Startup
基本相同:
:
[Fact]
public async Task GetSwaggerUI_Returns_OK()
await using var application = new TodoApplication();
var client = application.CreateClient();
var response = await client.GetAsync("/swagger/index.html");
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
class TodoApplication : WebApplicationFactory<Program>
protected override IHost CreateHost(IHostBuilder builder)
// Add mock/test services to the builder here
builder.ConfigureServices(services =>
services.AddScoped(sp =>
// Replace SQL Lite with test DB
return new SqliteConnection("Data Source=testtodos.db");
);
);
return base.CreateHost(builder);
该示例中的Program class 定义了很多端点:
using System.ComponentModel.DataAnnotations;
using Microsoft.Data.Sqlite;
using Dapper;
var builder = WebApplication.CreateBuilder(args);
var connectionString = builder.Configuration.GetConnectionString("TodoDb") ?? "Data Source=todos.db";
builder.Services.AddScoped(_ => new SqliteConnection(connectionString));
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
await EnsureDb(app.Services, app.Logger);
if (!app.Environment.IsDevelopment())
app.UseExceptionHandler("/error");
app.MapGet("/error", () => Results.Problem("An error occurred.", statusCode: 500))
.ExcludeFromDescription();
app.MapSwagger();
app.UseSwaggerUI();
app.MapGet("/", () => "Hello World!")
.WithName("Hello");
...
app.MapDelete("/todos/delete-all", async (SqliteConnection db) => Results.Ok(await db.ExecuteAsync("DELETE FROM Todos")))
.WithName("DeleteAll")
.Produces<int>(StatusCodes.Status200OK);
app.Run();
【讨论】:
在生成的项目中,也没有Program类。在您的示例中,您使用了程序类,但未定义它。 Program.cs 没有任何像以前那样的类定义。Program
类是从Program.cs
中的***语句自动生成的。我发布了那个 repo 的 Program.cs
的内容。没有class Program
,文件的内容被添加到编译器生成的Program
类中
@Daan .NET 6 RC1 已于上周发布,因此使用 WebApplicationFactory<Program>
现在可以使用
@Daan 你加了InternalsVisibleTo
吗?
@Daan 是的,你需要添加 InternalsVisible 来测试项目。我在 web 解决方案的 assemblyInfo 中添加了它。以上是关于如何使用 WebApplicationFactory 对 .NET 6 Web Api 项目进行集成测试?的主要内容,如果未能解决你的问题,请参考以下文章
如何在自动布局中使用约束标识符以及如何使用标识符更改约束? [迅速]
如何使用 AngularJS 的 ng-model 创建一个数组以及如何使用 jquery 提交?