编写第一个测试
更新: 2026-10-16 15:20:09 字数: 0 字 时长: 0 分钟
这一页演示如何为 Aspire 解决方案创建测试项目、编写并运行测试。它们不是单元测试,而是验证分布式应用各组件协作方式的功能测试与集成测试。
Aspire 提供了 xUnit.net、MSTest、NUnit 三种测试项目模板。
1. 创建测试项目
bash
dotnet new aspire-xunit -o xUnit.Testsbash
dotnet new aspire-xunit -o xUnit.Testsbash
dotnet new aspire-mstest -o MSTest.Testsbash
dotnet new aspire-nunit -o NUnit.Tests创建后进入目录:
bash
cd xUnit.Tests2. 引用 AppHost 项目
测试项目必须能引用到被测的 AppHost:
bash
dotnet add reference ../AspireApp.AppHost/AspireApp.AppHost.csproj为什么要引用 AppHost?
DistributedApplicationTestingBuilder 需要在同一进程内加载 AppHost 的类型(包括源码生成的 Projects.* 类型),因此必须有项目引用。
然后取消注释模板里的 IntegrationTest1.cs 即可开始。
3. 一个完整的测试
csharp
[Fact]
public async Task WebFrontend_Should_Return_Success()
{
// 1. 创建测试宿主
var appHost = await DistributedApplicationTestingBuilder
.CreateAsync<Projects.AspireApp_AppHost>();
await using var app = await appHost.BuildAsync();
// 2. 启动应用
await app.StartAsync();
// 3. 等待资源就绪(务必带超时)
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(60));
await app.ResourceNotifications.WaitForResourceHealthyAsync("webfrontend", cts.Token);
// 4. 发起请求并断言
using var client = app.CreateHttpClient("webfrontend");
var response = await client.GetAsync("/", cts.Token);
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
}4. 访问资源做更真实的校验
访问 HTTP 端点
csharp
using var client = app.CreateHttpClient("apiservice");
var json = await client.GetStringAsync("/weatherforecast");
Assert.Contains("temperatureC", json);如果资源有多个端点,可以指定端点名:
csharp
using var client = app.CreateHttpClient("apiservice", endpointName: "http");访问数据库验证状态
csharp
var connectionString = await app.GetConnectionStringAsync("catalogdb");
await using var connection = new NpgsqlConnection(connectionString);
await connection.OpenAsync();
var count = (long)await new NpgsqlCommand("SELECT COUNT(*) FROM \"Products\"", connection)
.ExecuteScalarAsync();
Assert.True(count > 0);等待单个资源
csharp
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30));
await app.ResourceNotifications.WaitForResourceAsync(
"apiservice",
KnownResourceStates.Running,
cts.Token);Running 不等于可服务
资源进入 KnownResourceStates.Running 只表示开始执行,不代表已经可以响应请求。如果资源配置了健康检查,请改用 WaitForResourceHealthyAsync。
5. 验证资源注解
除了功能测试,也可以断言 AppHost 中声明的资源与注解是否符合预期:
csharp
[Fact]
public async Task Resource_Should_Have_Expected_Annotations()
{
var appHost = await DistributedApplicationTestingBuilder
.CreateAsync<Projects.MyApp_AppHost>();
await using var app = await appHost.BuildAsync();
var resource = app.Resources.GetResource("my-resource");
Assert.NotEmpty(resource.Annotations.OfType<ServiceMetricsAnnotation>());
var metricsConfig = resource.Annotations
.OfType<ServiceMetricsAnnotation>()
.First();
Assert.True(metricsConfig.Enabled);
Assert.Equal("/metrics", metricsConfig.MetricsPath);
}这类测试非常适合做「架构回归」:它能保证别人改 AppHost 时不会悄悄去掉关键配置。
6. 在 CI 中运行
bash
dotnet testCI 需要容器运行时
Aspire 测试会启动容器化资源(数据库、缓存等)。CI Runner 必须具备可用的容器运行时,否则测试会在启动资源阶段失败。
在流水线中建议:
- 为测试设置合理的整体超时。
- 使用
ASPIRE_CONTAINER_RUNTIME明确指定容器运行时(如 Runner 上为 Podman)。 - 失败时收集
aspire export产物或容器日志,便于定位。
常见问题
测试偶尔失败,重跑又好了
典型的启动竞态。请确认:
- 在测试中使用
WaitForResourceHealthyAsync而不是固定Task.Delay。 - AppHost 中被依赖的资源声明了健康检查。
- 消费方资源使用了
WaitFor。
端口随机化导致我拿不到固定地址
这是特性而非缺陷:随机端口让多个测试实例可以并发运行。请始终通过 app.CreateHttpClient(...) 获取客户端,不要在测试里硬编码端口。
想在测试时看仪表板
csharp
configureBuilder: (appOptions, hostSettings) =>
{
appOptions.DisableDashboard = false;
}




