Communityコーディング&開発github.com

Akka.NET テストパターン

Akka.Hosting.TestKit を使用して Akka.NET アクターのユニットテストと統合テストを記述します。依存性注入、TestProbe、永続性テスト、アクター間のやり取りの検証を網羅します。従来の TestKit をいつ使用すべきかのガイダンスも含みます。

Akka.NET テストパターン とは?

このスキルは、Akka.Hosting.TestKit を使用した Akka.NET アクターのテストパターンを包括的に提供します。最新の .NET アプリケーションで広く使われる Microsoft.Extensions.DependencyInjection との統合を前提としており、本番環境と同じ構成でアクターをテストできます。主要な機能として、依存性注入によるモック/フェイクの注入、TestProbe を用いたアクター間メッセージの検証、イベントソーシングを用いた永続アクターのテスト、さらにはクラスタシャーディングのローカルテストまでサポートします。各パターンは具体例とともに説明され、File Watcher の問題を回避する重要な初期化コードも含まれています。主に Akka.NET v1.5 以降のプロジェクトを対象とし、Akka.Hosting.TestKit を推奨しますが、従来の Akka.TestKit をいつ使うべきかについても適切にガイドします。

対応~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 アクターのユニットテストを作成する場合
  • イベントソーシングを使用する永続アクターをテストする場合
  • アクター間の相互作用とメッセージフローを検証する場合
  • アクターの監視とライフサイクルをテストする場合
  • アクターテストで外部依存関係をモックする場合
  • クラスタシャーディングの動作をローカルでテストする場合
  • アクターの状態復元と永続性を検証する場合

参照ファイル

  • examples.md: すべてのテストパターン(パターン1〜8 + リマインダー)の完全なコードサンプル
  • anti-patterns-and-reference.md: アンチパターン、従来の TestKit、CI/CD 統合

テストアプローチの選択

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+)で作業している場合

利点:

  • ネイティブな依存性注入サポート - テストでサービスをフェイクでオーバーライド可能
  • 本番環境との構成パリティ(同じ拡張メソッドがテストでも動作)
  • アクターロジックとインフラストラクチャの明確な分離
  • アクター取得のためのタイプセーフなアクターレジストリ

従来の Akka.TestKit を使用する

使用するタイミング:

  • Akka.NET コアライブラリの開発に貢献する場合
  • Microsoft.Extensions がない環境(コンソールアプリ、レガシーシステム)で作業している場合
  • DI なしで手動の Props 作成を使用するレガシーコードベース

従来の TestKit パターンについては、anti-patterns-and-reference.md を参照してください。


コア原則(Akka.Hosting.TestKit)

  1. Akka.Hosting.TestKit.TestKit から継承する - これはフレームワークのベースクラスであり、ユーザー定義ではありません
  2. ConfigureServices() をオーバーライドする - 実際のサービスをフェイク/モックで置き換える
  3. ConfigureAkka() をオーバーライドする - 本番環境と同じ拡張メソッドを使用してアクターを構成する
  4. ActorRegistry を使用する - アクター参照のタイプセーフな取得
  5. 継承よりコンポジション - ベースクラスではなく、フィールドとしてフェイクサービスを持つ
  6. カスタムベースクラスなし - 継承階層ではなく、メソッドオーバーライドを使用する
  7. 一度に1つのアクターをテストする - 依存関係には 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="*" />

  <!-- アサーション(推奨) -->
  <PackageReference Include="FluentAssertions" Version="*" />

  <!-- テスト用のインメモリ永続性 -->
  <PackageReference Include="Akka.Persistence.Hosting" Version="*" />

  <!-- クラスタシャーディングをテストする場合 -->
  <PackageReference Include="Akka.Cluster.Hosting" Version="*" />
</ItemGroup>

重要:テストプロジェクトの File Watcher 修正

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

依存アクターの代役として TestProbe を ActorRegistry に登録します。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:ローカルでのクラスタシャーディング

AkkaExecutionMode.LocalTest と GenericChildPerEntityParent を使用して、実際のクラスタなしでシャーディング動作をテストします。同じ拡張メソッド、異なるモード。

パターン7:非同期操作のための AwaitAssertAsync

アクターが非同期操作を実行する場合は AwaitAssertAsync を使用します。アサーションが成功するかタイムアウトになるまで再試行し、flaky テストを防ぎます。

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

パターン8:シナリオベースの統合テスト

複数のアクターと状態遷移を持つ完全なビジネスワークフローをエンドツーエンドでテストします。すべてのドメインアクターを登録し、各ステップで状態を検証します。


共通パターンのまとめ

パターンユースケース
基本アクターテスト注入されたサービスを持つ単一アクター
TestProbeアクターが依存関係にメッセージを送信することを検証
自動応答テスト時の Ask タイムアウトを回避
永続アクターイベントソーシングと復旧をテスト
クラスタシャーディングローカルでシャーディング動作をテスト
AwaitAssertAsyncアクター内の非同期操作を処理
シナリオテストエンドツーエンドのビジネスワークフロー

ベストプラクティス

  1. アクターごとに1つのテストクラス - テストを集中させる
  2. ConfigureServices/ConfigureAkka をオーバーライド - ベースクラスを作成しない
  3. モックではなくフェイクを使用 - よりシンプルで保守性が高い
  4. 一度に1つのアクターをテスト - 依存関係には TestProbe を使用
  5. 本番パターンに合わせる - 同じ拡張メソッド、異なる AkkaExecutionMode
  6. 非同期には AwaitAssertAsync を使用 - flaky テストを防ぐ
  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.

関連スキル