Skip to content

编写第一个测试 ​

更新: 2026-10-16 15:20:09   字数: 0 字   时长: 0 分钟

这一页演示如何为 Aspire 解决方案创建测试项目、编写并运行测试。它们不是单元测试,而是验证分布式应用各组件协作方式的功能测试与集成测试。

Aspire 提供了 xUnit.net、MSTest、NUnit 三种测试项目模板。

1. 创建测试项目 ​

bash
dotnet new aspire-xunit -o xUnit.Tests
bash
dotnet new aspire-xunit -o xUnit.Tests
bash
dotnet new aspire-mstest -o MSTest.Tests
bash
dotnet new aspire-nunit -o NUnit.Tests

创建后进入目录:

bash
cd xUnit.Tests

2. 引用 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 test

CI 需要容器运行时

Aspire 测试会启动容器化资源(数据库、缓存等)。CI Runner 必须具备可用的容器运行时,否则测试会在启动资源阶段失败。

在流水线中建议:

  • 为测试设置合理的整体超时。
  • 使用 ASPIRE_CONTAINER_RUNTIME 明确指定容器运行时(如 Runner 上为 Podman)。
  • 失败时收集 aspire export 产物或容器日志,便于定位。

常见问题 ​

测试偶尔失败,重跑又好了

典型的启动竞态。请确认:

  1. 在测试中使用 WaitForResourceHealthyAsync 而不是固定 Task.Delay。
  2. AppHost 中被依赖的资源声明了健康检查。
  3. 消费方资源使用了 WaitFor。
端口随机化导致我拿不到固定地址

这是特性而非缺陷:随机端口让多个测试实例可以并发运行。请始终通过 app.CreateHttpClient(...) 获取客户端,不要在测试里硬编码端口。

想在测试时看仪表板
csharp
configureBuilder: (appOptions, hostSettings) =>
{
    appOptions.DisableDashboard = false;
}

下一步 ​

你觉得这篇文章怎么样?
  • 0
  • 0
  • 0
  • 0
  • 0
  • 0
评论
  • 按正序
  • 按倒序
  • 按热度