Aspire Integration Testing

aaronontheweb/dotnet-skills/skills/aspire-integration-testing

作者 aarononthewebe426ed93a9f3无许可证1.2K 个星标收录于 2026年10月8日更新于 2026年10月8日仓库3周前更新

Write integration tests using .NET Aspire's testing facilities with xUnit. Covers test fixtures, distributed application setup, endpoint discovery, and patterns for testing ASP.NET Core apps with real dependencies.

AI 生成的概览

指导使用 xUnit 编写 .NET Aspire 集成测试,涵盖测试夹具、分布式应用启动与终结点发现。

功能
该技能提供使用 xUnit 为 .NET Aspire 应用编写集成测试的说明和代码模式。内容涵盖基于 IAsyncLifetime 的测试夹具、从 AppHost 启动 DistributedApplication、动态终结点发现、健康检查等待,以及针对真实容器化依赖测试 ASP.NET Core 应用。它还指向高级模式和 CI 工具相关的参考文件。
适用场景
适用于为需要真实基础设施(如 SQL Server、Redis 或消息队列)的 .NET Aspire 或 ASP.NET Core 应用编写集成测试。也适合测试分布式应用中的服务间通信,或将 Playwright UI 测试与 Aspire 编排的服务结合使用。
运行要求
需要一个包含 xUnit、Aspire.Hosting.Testing、xunit.runner.visualstudio 和 Microsoft.NET.Test.Sdk 包的 .NET 测试项目,以及一个 Aspire AppHost 项目。测试需要容器运行时访问权限以使用真实依赖。该技能不附带脚本,仅为说明文档。

Integration Testing with .NET Aspire + xUnit

When to Use This Skill

Use this skill when:

  • Writing integration tests for .NET Aspire applications
  • Testing ASP.NET Core apps with real database connections
  • Verifying service-to-service communication in distributed applications
  • Testing with actual infrastructure (SQL Server, Redis, message queues) in containers
  • Combining Playwright UI tests with Aspire-orchestrated services
  • Testing microservices with proper service discovery and networking

Reference Files

  • advanced-patterns.md [blocked]: Endpoint discovery, database testing, Playwright, conditional config, Respawn, service communication, message queues
  • ci-and-tooling.md [blocked]: CI/CD integration, custom resource waiters, Aspire CLI with MCP

Core Principles

  1. Real Dependencies - Use actual infrastructure (databases, caches) via Aspire, not mocks
  2. Dynamic Port Binding - Let Aspire assign ports dynamically (127.0.0.1:0) to avoid conflicts
  3. Fixture Lifecycle - Use IAsyncLifetime for proper test fixture setup and teardown
  4. Endpoint Discovery - Never hard-code URLs; discover endpoints from Aspire at runtime
  5. Parallel Isolation - Use xUnit collections to control test parallelization
  6. Health Checks - Always wait for services to be healthy before running tests

High-Level Testing Architecture

┌─────────────────┐                    ┌──────────────────────┐│ xUnit test file │──uses────────────►│  AspireFixture       │└─────────────────┘                    │  (IAsyncLifetime)    │                                       └──────────────────────┘                                               │                                               │ starts                                               ▼                                    ┌───────────────────────────┐                                    │  DistributedApplication   │                                    │  (from AppHost)           │                                    └───────────────────────────┘                                               │ exposes                                               ▼                                  ┌──────────────────────────────┐                                  │   Dynamic HTTP Endpoints     │                                  └──────────────────────────────┘                                               │ consumed by                                               ▼                                   ┌─────────────────────────┐                                   │  HttpClient / Playwright│                                   └─────────────────────────┘

Required NuGet Packages

xml
<ItemGroup>  <PackageReference Include="Aspire.Hosting.Testing" Version="$(AspireVersion)" />  <PackageReference Include="xunit" Version="*" />  <PackageReference Include="xunit.runner.visualstudio" Version="*" />  <PackageReference Include="Microsoft.NET.Test.Sdk" Version="*" /></ItemGroup>

CRITICAL: File Watcher Fix for Integration Tests

When running many integration tests that each start an IHost, the default .NET host builder enables file watchers for configuration reload. This exhausts file descriptor limits on Linux.

Add this to your test project before any tests run:

csharp
// TestEnvironmentInitializer.csusing System.Runtime.CompilerServices;
namespace YourApp.Tests;
internal static class TestEnvironmentInitializer{    [ModuleInitializer]    internal static void Initialize()    {        // Disable config file watching in test hosts        // Prevents file descriptor exhaustion (inotify watch limit) on Linux        Environment.SetEnvironmentVariable("DOTNET_HOSTBUILDER__RELOADCONFIGONCHANGE", "false");    }}

Pattern 1: Basic Aspire Test Fixture (Modern API)

csharp
using Aspire.Hosting;using Aspire.Hosting.Testing;
public sealed class AspireAppFixture : IAsyncLifetime{    private DistributedApplication? _app;
    public DistributedApplication App => _app        ?? throw new InvalidOperationException("App not initialized");
    public async Task InitializeAsync()    {        var builder = await DistributedApplicationTestingBuilder            .CreateAsync<Projects.YourApp_AppHost>([                "YourApp:UseVolumes=false",                "YourApp:Environment=IntegrationTest",                "YourApp:Replicas=1"            ]);
        _app = await builder.BuildAsync();
        using var startupCts = new CancellationTokenSource(TimeSpan.FromMinutes(10));        await _app.StartAsync(startupCts.Token);
        using var healthCts = new CancellationTokenSource(TimeSpan.FromMinutes(5));        await _app.ResourceNotifications.WaitForResourceHealthyAsync("api", healthCts.Token);    }
    public Uri GetEndpoint(string resourceName, string scheme = "https")    {        return _app?.GetEndpoint(resourceName, scheme)            ?? throw new InvalidOperationException($"Endpoint for '{resourceName}' not found");    }
    public async Task DisposeAsync()    {        if (_app is not null)        {            await _app.DisposeAsync();        }    }}

Pattern 2: Using the Fixture in Tests

csharp
[CollectionDefinition("Aspire collection")]public class AspireCollection : ICollectionFixture<AspireAppFixture> { }
[Collection("Aspire collection")]public class IntegrationTests{    private readonly AspireAppFixture _fixture;
    public IntegrationTests(AspireAppFixture fixture)    {        _fixture = fixture;    }
    [Fact]    public async Task Application_ShouldStart()    {        var httpClient = _fixture.App.CreateHttpClient("yourapp");        var response = await httpClient.GetAsync("/");        Assert.Equal(HttpStatusCode.OK, response.StatusCode);    }}

See advanced-patterns.md [blocked] for Endpoint Discovery, Database Testing, Playwright UI Tests, Conditional Resource Configuration, Respawn database reset, Service-to-Service Communication, and Message Queue testing patterns.

Common Patterns Summary

PatternUse Case
Basic FixtureSimple HTTP endpoint testing
Endpoint DiscoveryAvoid hard-coded URLs
Database TestingVerify data access layer
Playwright IntegrationFull UI testing with real backend
Configuration OverrideTest-specific settings
Health ChecksEnsure services are ready
Service CommunicationTest distributed system interactions
Message Queue TestingVerify async messaging

Tricky / Non-Obvious Tips

ProblemSolution
Tests timeout immediatelyCall await _app.StartAsync() and wait for services to be healthy
Port conflicts between testsUse xUnit CollectionDefinition to share fixtures
Flaky tests due to timingImplement proper health check polling instead of Task.Delay()
Can't connect to SQL ServerRetrieve connection string dynamically via GetConnectionStringAsync()
Parallel tests interfereUse [Collection] attribute to run related tests sequentially
Aspire dashboard conflictsOnly one dashboard can run at a time; tests reuse the same instance

Best Practices

  1. Use IAsyncLifetime - Ensures proper async initialization and cleanup
  2. Share fixtures via collections - Reduces test execution time by reusing app instances
  3. Discover endpoints dynamically - Never hard-code localhost:5000 or similar
  4. Wait for health checks - Don't assume services are immediately ready
  5. Test with real dependencies - Aspire makes it easy to use real SQL, Redis, etc.
  6. Clean up resources - Always implement DisposeAsync properly
  7. Use meaningful test data - Seed databases with realistic test data
  8. Test failure scenarios - Verify error handling and resilience
  9. Keep tests isolated - Each test should be independent and order-agnostic
  10. Monitor test execution time - If tests are slow, consider parallelization

See ci-and-tooling.md [blocked] for GitHub Actions setup, custom resource waiters, and Aspire CLI/MCP integration.


Debugging Tips

  1. Run Aspire Dashboard - When tests fail, check the dashboard at http://localhost:15888
  2. Use Aspire CLI with MCP - Let AI assistants query real application state
  3. Enable detailed logging - Set ASPIRE_ALLOW_UNSECURED_TRANSPORT=true for more verbose output
  4. Check container logs - Use docker logs to inspect container output
  5. Use breakpoints in fixtures - Debug fixture initialization to catch startup issues
  6. Verify resource names - Ensure resource names match between AppHost and tests

来源与署名

来源:aaronontheweb/dotnet-skills位于skills/aspire-integration-testing提交e426ed9

许可证: 无许可证

内容归原作者所有。SourceWeft 从公开仓库中收录这些内容。

举报或申请下架