Community코딩 & 개발github.com

aspire-통합-테스팅

.NET Aspire 애플리케이션을 위한 통합 테스트 작성

aspire-통합-테스팅란 무엇인가요?

이 스킬은 .NET Aspire와 xUnit을 사용하여 통합 테스트를 작성하고 실행하는 방법을 제공합니다. Aspire의 `DistributedApplication`을 활용하여 실제 데이터베이스(SQL Server, Redis), 메시지 큐, Playwright UI 등과 같은 실제 인프라를 포함하는 통합 테스트를 손쉽게 구성할 수 있습니다. 핵심 원칙으로는 실제 의존성 사용, 동적 포트 바인딩, 엔드포인트 자동 발견, 건강 상태 확인(Health Check) 대기 등이 있으며, xUnit의 컬렉션 기능을 통해 테스트 병렬화를 제어하고 파일 디스크립터 고갈 문제를 방지하기 위한 환경 변수 설정을 포함합니다. 주요 패턴으로는 기본 Aspire 테스트 픽스처, 데이터베이스 테스팅, Playwright 통합, 서비스 간 통신 테스트, 메시지 큐 테스트 등이 있으며, GitHub Actions, Docker, Aspire CLI와의 연동도 지원합니다.

지원 대상~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/Aaronontheweb/dotnet-skills/tree/main/skills/aspire-integration-testing

Installed? Explore more 코딩 & 개발 skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

즐겨 사용하는 AI에게 물어보기

이 에이전트 스킬이 미리 로드된 새 채팅을 엽니다.

문서

.NET Aspire + xUnit을 사용한 통합 테스팅

이 스킬을 사용해야 하는 경우

다음과 같은 경우에 이 스킬을 사용하세요:

  • .NET Aspire 애플리케이션에 대한 통합 테스트를 작성할 때
  • 실제 데이터베이스 연결로 ASP.NET Core 앱을 테스트할 때
  • 분산 애플리케이션에서 서비스 간 통신을 확인할 때
  • 컨테이너에서 실제 인프라(SQL Server, Redis, 메시지 큐)로 테스트할 때
  • Playwright UI 테스트와 Aspire로 조정된 서비스를 결합할 때
  • 적절한 서비스 검색 및 네트워킹을 사용하여 마이크로서비스를 테스트할 때

참조 파일

  • advanced-patterns.md: 엔드포인트 검색, 데이터베이스 테스팅, Playwright, 조건부 구성, Respawn, 서비스 통신, 메시지 큐
  • ci-and-tooling.md: CI/CD 통합, 사용자 정의 리소스 웨이터, MCP를 사용한 Aspire CLI

핵심 원칙

  1. 실제 의존성 - 모의 객체가 아닌 Aspire를 통해 실제 인프라(데이터베이스, 캐시)를 사용합니다.
  2. 동적 포트 바인딩 - Aspire가 포트를 동적으로 할당하도록 합니다(127.0.0.1:0). 충돌을 방지합니다.
  3. 픽스처 생명주기 - 적절한 테스트 픽스처 설정 및 정리를 위해 IAsyncLifetime을 사용합니다.
  4. 엔드포인트 검색 - URL을 하드코딩하지 말고, 런타임에 Aspire에서 엔드포인트를 검색합니다.
  5. 병렬 격리 - xUnit 컬렉션을 사용하여 테스트 병렬화를 제어합니다.
  6. 건강 상태 확인 - 테스트를 실행하기 전에 항상 서비스가 정상 상태가 될 때까지 기다립니다.

고수준 테스팅 아키텍처

┌─────────────────┐                    ┌──────────────────────┐
│ xUnit 테스트 파일 │──사용함──────────►│  AspireFixture       │
└─────────────────┘                    │  (IAsyncLifetime)    │
                                       └──────────────────────┘
                                               │
                                               │ 시작
                                               ▼
                                    ┌───────────────────────────┐
                                    │  DistributedApplication  │
                                    │  (AppHost에서)           │
                                    └───────────────────────────┘
                                               │ 노출
                                               ▼
                                  ┌──────────────────────────────┐
                                  │   동적 HTTP 엔드포인트      │
                                  └──────────────────────────────┘
                                               │ 소비됨
                                               ▼
                                   ┌─────────────────────────┐
                                   │  HttpClient / Playwright│
                                   └─────────────────────────┘

필수 NuGet 패키지

<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>

중요: 통합 테스트용 파일 감시자 수정

각각 IHost를 시작하는 여러 통합 테스트를 실행할 때, 기본 .NET 호스트 빌더는 구성 다시 로드를 위해 파일 감시자를 활성화합니다. 이로 인해 Linux에서 파일 디스크립터 제한이 소진됩니다.

테스트 프로젝트에 테스트가 실행되기 전에 다음을 추가하세요:

// TestEnvironmentInitializer.cs
using System.Runtime.CompilerServices;

namespace YourApp.Tests;

internal static class TestEnvironmentInitializer
{
    [ModuleInitializer]
    internal static void Initialize()
    {
        // 테스트 호스트에서 구성 파일 감시 비활성화
        // Linux에서 파일 디스크립터 고갈(inotify 감시 한계) 방지
        Environment.SetEnvironmentVariable("DOTNET_HOSTBUILDER__RELOADCONFIGONCHANGE", "false");
    }
}

패턴 1: 기본 Aspire 테스트 픽스처 (최신 API)

using Aspire.Hosting;
using Aspire.Hosting.Testing;

public sealed class AspireAppFixture : IAsyncLifetime
{
    private DistributedApplication? _app;

    public DistributedApplication App => _app
        ?? throw new InvalidOperationException("앱이 초기화되지 않았습니다");

    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($"'{resourceName}'에 대한 엔드포인트를 찾을 수 없습니다");
    }

    public async Task DisposeAsync()
    {
        if (_app is not null)
        {
            await _app.DisposeAsync();
        }
    }
}

패턴 2: 테스트에서 픽스처 사용

[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);
    }
}

고급 패턴에 대해서는 advanced-patterns.md를 참조하세요: 엔드포인트 검색, 데이터베이스 테스팅, Playwright UI 테스트, 조건부 리소스 구성, Respawn 데이터베이스 재설정, 서비스 간 통신, 메시지 큐 테스트 패턴.

일반 패턴 요약

패턴사용 사례
기본 픽스처간단한 HTTP 엔드포인트 테스팅
엔드포인트 검색하드코딩된 URL 방지
데이터베이스 테스팅데이터 액세스 계층 확인
Playwright 통합실제 백엔드와 함께 전체 UI 테스팅
구성 재정의테스트별 설정
건강 상태 확인서비스가 준비되었는지 확인
서비스 통신분산 시스템 상호 작용 테스트
메시지 큐 테스팅비동기 메시징 확인

까다롭거나 명확하지 않은 팁

문제해결책
테스트가 즉시 타임아웃됨await _app.StartAsync()를 호출하고 서비스가 정상 상태가 될 때까지 기다립니다.
테스트 간 포트 충돌xUnit CollectionDefinition을 사용하여 픽스처를 공유합니다.
타이밍으로 인한 불안정한 테스트Task.Delay() 대신 적절한 건강 상태 확인 폴링을 구현합니다.
SQL Server에 연결할 수 없음GetConnectionStringAsync()를 통해 연결 문자열을 동적으로 검색합니다.
병렬 테스트 간섭[Collection] 특성을 사용하여 관련 테스트를 순차적으로 실행합니다.
Aspire 대시보드 충돌한 번에 하나의 대시보드만 실행할 수 있습니다. 테스트는 동일한 인스턴스를 재사용합니다.

모범 사례

  1. IAsyncLifetime 사용 - 적절한 비동기 초기화 및 정리를 보장합니다.
  2. 컬렉션을 통해 픽스처 공유 - 앱 인스턴스를 재사용하여 테스트 실행 시간을 줄입니다.
  3. 엔드포인트를 동적으로 검색 - localhost:5000 등을 하드코딩하지 마십시오.
  4. 건강 상태 확인 대기 - 서비스가 즉시 준비되었다고 가정하지 마십시오.
  5. 실제 의존성으로 테스트 - Aspire를 사용하면 실제 SQL, Redis 등을 쉽게 사용할 수 있습니다.
  6. 리소스 정리 - 항상 DisposeAsync를 올바르게 구현합니다.
  7. 의미 있는 테스트 데이터 사용 - 데이터베이스를 현실적인 테스트 데이터로 시드합니다.
  8. 실패 시나리오 테스트 - 오류 처리 및 복원력을 확인합니다.
  9. 테스트 격리 유지 - 각 테스트는 독립적이고 순서에 영향을 받지 않아야 합니다.
  10. 테스트 실행 시간 모니터링 - 테스트가 느리면 병렬화를 고려합니다.

GitHub Actions 설정, 사용자 정의 리소스 웨이터, Aspire CLI/MCP 통합에 대해서는 ci-and-tooling.md를 참조하세요.


디버깅 팁

  1. Aspire 대시보드 실행 - 테스트가 실패하면 http://localhost:15888에서 대시보드를 확인합니다.
  2. MCP와 함께 Aspire CLI 사용 - AI 도우미가 실제 애플리케이션 상태를 쿼리하도록 합니다.
  3. 상세 로깅 활성화 - 더 자세한 출력을 위해 ASPIRE_ALLOW_UNSECURED_TRANSPORT=true를 설정합니다.
  4. 컨테이너 로그 확인 - docker logs를 사용하여 컨테이너 출력을 검사합니다.
  5. 픽스처에서 중단점 사용 - 픽스처 초기화를 디버깅하여 시작 문제를 잡습니다.
  6. 리소스 이름 확인 - AppHost와 테스트 간에 리소스 이름이 일치하는지 확인합니다.

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

akka-hosting-actor-patterns

Patterns for building entity actors with Akka.Hosting - GenericChildPerEntityParent, message extractors, cluster sharding abstraction, akka-reminders, and ITimeProvider. Supports both local testing and clustered production modes.

akka-net-aspire-configuration

Configure Akka.NET with .NET Aspire for local development and production deployments. Covers actor system setup, clustering, persistence, Akka.Management integration, and Aspire orchestration patterns.

akka-net-best-practices

Critical Akka.NET best practices including EventStream vs DistributedPubSub, supervision strategies, error handling, Props vs DependencyResolver, work distribution patterns, and cluster/local mode abstractions for testability.

akka-net-management

Akka.Management for cluster bootstrapping, service discovery (Kubernetes, Azure, Config), health checks, and dynamic cluster formation without static seed nodes.

akka-net-testing-patterns

Write unit and integration tests for Akka.NET actors using modern Akka.Hosting.TestKit patterns. Covers dependency injection, TestProbes, persistence testing, and actor interaction verification. Includes guidance on when to use traditional TestKit.

api-design

Design stable, compatible public APIs using extend-only design principles. Manage API compatibility, wire compatibility, and versioning for NuGet packages and distributed systems.

aspire-configuration

Configure Aspire AppHost to emit explicit app config via environment variables; keep app code free of Aspire clients and service discovery.

aspire-service-defaults

Create a shared ServiceDefaults project for Aspire applications. Centralizes OpenTelemetry, health checks, resilience, and service discovery configuration across all services.

crap-analysis

Analyze code coverage and CRAP (Change Risk Anti-Patterns) scores to identify high-risk code. Use OpenCover format with ReportGenerator for Risk Hotspots showing cyclomatic complexity and untested code paths.

csharp-concurrency-patterns

Choosing the right concurrency abstraction in .NET - from async/await for I/O to Channels for producer/consumer to Akka.NET for stateful entity management. Avoid locks and manual synchronization unless absolutely necessary.

database-performance

Database access patterns for performance. Separate read/write models, avoid N+1 queries, use AsNoTracking, apply row limits, and never do application-side joins. Works with EF Core and Dapper.

dependency-injection-patterns

Organize DI registrations using IServiceCollection extension methods. Group related services into composable Add* methods for clean Program.cs and reusable configuration in tests.

dotnet-devcert-trust

Diagnose and fix .NET HTTPS dev certificate trust issues on Linux. Covers the full certificate lifecycle from generation to system CA bundle inclusion, with distro-specific guidance for Ubuntu, Fedora, Arch, and WSL2.

dotnet-local-tools

Managing local .NET tools with dotnet-tools.json for consistent tooling across development environments and CI/CD pipelines.

dotnet-project-structure

Modern .NET project structure including .slnx solution format, Directory.Build.props, central package management, SourceLink, version management with RELEASE_NOTES.md, and SDK pinning with global.json.

dotnet-slopwatch

Use Slopwatch to detect LLM reward hacking in .NET code changes. Run after every code modification to catch disabled tests, suppressed warnings, empty catch blocks, and other shortcuts that mask real problems.

efcore-patterns

Entity Framework Core best practices including NoTracking by default, query splitting for navigation collections, migration management, dedicated migration services, and common pitfalls to avoid.

ilspy-decompile

Understand implementation details of .NET code by decompiling assemblies. Use when you want to see how a .NET API works internally, inspect NuGet package source, view framework implementation, or understand compiled .NET binaries.

mailpit-integration

Test email sending locally using Mailpit with .NET Aspire. Captures all outgoing emails without sending them. View rendered HTML, inspect headers, and verify delivery in integration tests.

marketplace-publishing

Workflow for publishing skills and agents to the dotnet-skills Claude Code marketplace. Covers adding new content, updating plugin.json, validation, and release tagging.

관련 스킬