Community코딩 & 개발github.com

akka-net-testing-patterns

Akka.NET 액터를 위한 단위 및 통합 테스트 작성 – 최신 Akka.Hosting.TestKit 패턴을 사용하여 의존성 주입, TestProbe, 영속성 테스트 및 액터 상호작용 검증을 다룹니다. 전통적인 TestKit을 사용해야 하는 경우에 대한 지침도 포함합니다.

akka-net-testing-patterns란 무엇인가요?

이 스킬은 Akka.NET 액터 시스템을 테스트하는 방법에 대한 포괄적인 가이드입니다. 특히 최신 Akka.Hosting.TestKit 패턴에 초점을 맞추어, 의존성 주입(DI), TestProbe를 통한 액터 간 메시지 상호작용 검증, 영속성(Persistence) 및 이벤트 소싱(Event Sourcing) 테스트, 클러스터 샤딩(Cluster Sharding) 로컬 테스트, 비동기 작업 검증(AwaitAssertAsync), 시나리오 기반 통합 테스트 등 8가지 주요 패턴을 코드 예제와 함께 제공합니다. 이 스킬은 Akka.NET v1.5 이상과 .NET의 Microsoft.Extensions.DependencyInjection을 사용하는 현대적인 애플리케이션 개발자에게 특히 유용합니다. 또한, 전통적인 Akka.TestKit을 사용해야 하는 레거시 환경이나 Akka.NET 코어 라이브러리 개발 상황도 함께 다루어, 적절한 테스트 접근 방식을 선택할 수 있도록 돕습니다. Linux 환경에서 많은 테스트 실행 시 발생할 수 있는 파일 디스크립터 고갈 문제(inotify 한계)를 해결하는 `DOTNET_HOSTBUILDER__RELOADCONFIGONCHANGE` 환경 변수 설정과 같은 운영 팁도 포함되어 있어 실무에서 바로 적용할 수 있습니다.

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

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

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

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

문서

Akka.NET 테스트 패턴

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

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

  • Akka.NET 액터의 단위 테스트 작성
  • 이벤트 소싱을 사용하는 영속성 액터 테스트
  • 액터 상호작용 및 메시지 흐름 검증
  • 액터 감독 및 생명주기 테스트
  • 액터 테스트에서 외부 의존성 모킹
  • 클러스터 샤딩 동작 로컬 테스트
  • 액터 상태 복구 및 영속성 검증

참조 파일

테스트 접근 방식 선택

Akka.Hosting.TestKit 사용 (95% 사용 사례에 권장)

사용 시기:

  • Microsoft.Extensions.DependencyInjection을 사용하는 현대적인 .NET 애플리케이션 구축
  • 프로덕션에서 Akka.Hosting을 사용하여 액터 구성
  • 액터에 서비스(IOptions, DbContext, ILogger, HTTP 클라이언트 등) 주입 필요
  • ASP.NET Core, Worker Services 또는 .NET Aspire를 사용하는 애플리케이션 테스트
  • 현대적인 Akka.NET 프로젝트 작업(Akka.NET v1.5 이상)

장점:

  • 네이티브 의존성 주입 지원 – 테스트에서 서비스를 페이크로 재정의 가능
  • 프로덕션과 구성 일관성 (동일한 확장 메서드가 테스트에서도 작동)
  • 액터 로직과 인프라의 깔끔한 분리
  • 액터 검색을 위한 타입 안전한 ActorRegistry

전통적인 Akka.TestKit 사용

사용 시기:

  • Akka.NET 코어 라이브러리 개발에 기여
  • Microsoft.Extensions가 없는 환경(콘솔 앱, 레거시 시스템)
  • DI 없이 수동 Props 생성을 사용하는 레거시 코드베이스

전통적인 TestKit 패턴은 anti-patterns-and-reference.md를 참조하세요.


핵심 원칙 (Akka.Hosting.TestKit)

  1. Akka.Hosting.TestKit.TestKit 상속 – 이는 사용자 정의 클래스가 아닌 프레임워크 기본 클래스입니다.
  2. ConfigureServices() 재정의 – 실제 서비스를 페이크/목(mock)으로 교체합니다.
  3. ConfigureAkka() 재정의 – 프로덕션과 동일한 확장 메서드를 사용하여 액터를 구성합니다.
  4. ActorRegistry 사용 – 타입 안전하게 액터 참조를 검색합니다.
  5. 상속보다 컴포지션 – 기본 클래스가 아닌 필드로 페이크 서비스를 사용합니다.
  6. 사용자 정의 기본 클래스 없음 – 상속 계층 대신 메서드 재정의를 사용합니다.
  7. 한 번에 하나의 액터 테스트 – 의존성에 TestProbe를 사용합니다.
  8. 프로덕션 패턴 일치 – 동일한 확장 메서드, 다른 AkkaExecutionMode

필수 NuGet 패키지

<ItemGroup>
  <!-- 코어 테스트 프레임워크 -->
  <PackageReference Include="Akka.Hosting.TestKit" Version="*" />

  <!-- xUnit (또는 선호하는 테스트 프레임워크) -->
  <PackageReference Include="xunit" Version="*" />
  <PackageReference Include="xunit.runner.visualstudio" Version="*" />
  <PackageReference Include="Microsoft.NET.Test.Sdk" Version="*" />

  <!-- Assertions (권장) -->
  <PackageReference Include="FluentAssertions" Version="*" />

  <!-- 테스트를 위한 인메모리 영속성 -->
  <PackageReference Include="Akka.Persistence.Hosting" Version="*" />

  <!-- 클러스터 샤딩 테스트 시 -->
  <PackageReference Include="Akka.Cluster.Hosting" Version="*" />
</ItemGroup>

중요: 테스트 프로젝트의 파일 감시자 수정

Akka.Hosting.TestKit은 실제 IHost 인스턴스를 생성하며, 기본적으로 구성 다시 로드를 위해 파일 감시자를 활성화합니다. 많은 테스트를 실행할 때 Linux에서 파일 디스크립터 한도(inotify 감시 한도)를 소진할 수 있습니다.

테스트 프로젝트에 다음을 추가하세요 – 모든 테스트 실행 전에 실행됩니다:

// 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");
    }
}

중요한 이유:

  • [ModuleInitializer]는 테스트 코드보다 먼저 자동으로 실행됩니다.
  • 모든 IHost 인스턴스에 대해 환경 변수를 전역적으로 설정합니다.
  • 100개 이상의 테스트 실행 시 발생하는 모호한 inotify 오류를 방지합니다.
  • IHost를 사용하는 Aspire 통합 테스트에도 적용됩니다.

테스트 패턴 개요

각 패턴은 간략하게 설명되어 있습니다. 완전한 코드 샘플은 examples.md를 참조하세요.

패턴 1: 기본 액터 테스트

기본 패턴입니다. ConfigureServices()를 재정의하여 페이크를 주입하고, ConfigureAkka()를 재정의하여 프로덕션과 동일한 확장 메서드로 액터를 등록합니다.

public class OrderActorTests : TestKit
{
    private readonly FakeOrderRepository _fakeRepository = new();

    protected override void ConfigureServices(HostBuilderContext context, IServiceCollection services)
    {
        services.AddSingleton<IOrderRepository>(_fakeRepository);
    }

    protected override void ConfigureAkka(AkkaConfigurationBuilder builder, IServiceProvider provider)
    {
        builder.WithInMemoryJournal().WithInMemorySnapshotStore();
        builder.WithActors((system, registry, resolver) =>
        {
            registry.Register<OrderActor>(system.ActorOf(resolver.Props<OrderActor>(), "order-actor"));
        });
    }

    [Fact]
    public async Task CreateOrder_Success_SavesToRepository()
    {
        var orderActor = ActorRegistry.Get<OrderActor>();
        var response = await orderActor.Ask<OrderCommandResult>(
            new CreateOrder("ORDER-123", "CUST-456", 99.99m), RemainingOrDefault);
        response.Status.Should().Be(CommandStatus.Success);
        _fakeRepository.SaveCallCount.Should().Be(1);
    }
}

패턴 2: 액터 상호작용을 위한 TestProbe

ActorRegistry에 TestProbe를 등록하여 의존성 액터 대신 사용합니다. ExpectMsgAsync<T>()를 사용하여 메시지가 전송되었는지 확인합니다.

패턴 3: 자동 응답 TestProbe

테스트 대상 액터가 Ask를 사용하여 의존성과 통신하는 경우, 프로브에 메시지를 전달하고 응답하여 타임아웃을 방지하는 자동 응답 액터를 생성합니다.

패턴 4: 영속성 액터 테스트

WithInMemoryJournal()와 WithInMemorySnapshotStore()를 사용합니다. PoisonPill로 액터를 종료하고 쿼리하여 저널에서 복구를 강제하는 방식으로 복구를 테스트합니다.

패턴 5: 프로덕션 구성 재사용

프로덕션 확장 메서드를 항상 재사용하고 HOCON 구성을 복제하지 마세요. 이렇게 하면 테스트가 프로덕션과 정확히 동일한 구성을 사용하게 됩니다.

protected override void ConfigureAkka(AkkaConfigurationBuilder builder, IServiceProvider provider)
{
    builder
        .AddDraftSerializer()                                    // 프로덕션과 동일
        .AddOrderDomainActors(AkkaExecutionMode.LocalTest)      // 동일하지만 로컬 모드
        .WithInMemoryJournal().WithInMemorySnapshotStore();      // 테스트별 재정의
}

패턴 6: 로컬에서 클러스터 샤딩

실제 클러스터 없이 샤딩 동작을 테스트하려면 GenericChildPerEntityParent와 함께 AkkaExecutionMode.LocalTest를 사용합니다. 동일한 확장 메서드, 다른 모드입니다.

패턴 7: 비동기 작업을 위한 AwaitAssertAsync

액터가 비동기 작업을 수행할 때 AwaitAssertAsync를 사용합니다. 어설션이 통과하거나 타임아웃이 발생할 때까지 재시도하여 불안정한 테스트를 방지합니다.

await AwaitAssertAsync(() =>
{
    _fakeReadModelService.SyncCallCount.Should().BeGreaterOrEqualTo(1);
}, TimeSpan.FromSeconds(3));

패턴 8: 시나리오 기반 통합 테스트

여러 액터와 상태 전환을 포함하는 완전한 비즈니스 워크플로를 종단 간 테스트합니다. 모든 도메인 액터를 등록하고 각 단계에서 상태를 확인합니다.


일반 패턴 요약

패턴사용 사례
기본 액터 테스트서비스가 주입된 단일 액터
TestProbe액터가 의존성에 메시지를 보내는지 확인
자동 응답테스트 시 Ask 타임아웃 방지
영속성 액터이벤트 소싱 및 복구 테스트
클러스터 샤딩로컬에서 샤딩 동작 테스트
AwaitAssertAsync액터의 비동기 작업 처리
시나리오 테스트종단 간 비즈니스 워크플로

모범 사례

  1. 액터당 하나의 테스트 클래스 – 테스트를 집중적으로 유지
  2. ConfigureServices/ConfigureAkka 재정의 – 기본 클래스를 만들지 마세요
  3. 목 대신 페이크 사용 – 더 간단하고 유지 관리가 용이함
  4. 한 번에 하나의 액터 테스트 – 의존성에 TestProbe 사용
  5. 프로덕션 패턴 일치 – 동일한 확장 메서드, 다른 AkkaExecutionMode
  6. 비동기에는 AwaitAssertAsync 사용 – 불안정한 테스트 방지
  7. 복구 테스트 – 액터를 종료하고 다시 시작하여 영속성 확인
  8. 워크플로 시나리오 테스트 – 완전한 비즈니스 흐름을 종단 간 테스트
  9. 테스트를 빠르게 유지 – 인메모리 영속성, 실제 데이터베이스 없음
  10. 의미 있는 이름 사용 – Scenario_FirstTimePurchase_SuccessfulPayment

디버깅 팁

  1. 디버그 로깅 활성화 – TestKit 생성자에 LogLevel.Debug 전달
  2. ITestOutputHelper 사용 – 테스트 출력에서 액터 시스템 로그 확인
  3. TestProbe 검사 – probe.Messages를 확인하여 전송된 메시지 확인
  4. 액터 상태 쿼리 – 디버깅을 위해 상태 쿼리 메시지 추가
  5. 로깅과 함께 AwaitAssertAsync 사용 – 어설션이 실패하는 이유 확인
  6. ActorRegistry 확인 – 액터가 올바르게 등록되었는지 확인
// 디버그 로깅이 있는 생성자
public OrderActorTests(ITestOutputHelper output)
    : base(output: output, logLevel: LogLevel.Debug)
{
}

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.

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

Write integration tests using .NET Aspire

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.

관련 스킬