O que Padrões de Teste para Akka.NET faz?
Quando Usar Esta Habilidade
Use esta habilidade quando:
- Escrever testes unitários para atores Akka.NET
- Testar atores persistentes com event sourcing
- Verificar interações entre atores e fluxos de mensagens
- Testar supervisão e ciclo de vida de atores
- Simular dependências externas em testes de atores
- Testar comportamento de cluster sharding localmente
- Verificar recuperação de estado e persistência de atores
Arquivos de Referência
- examples.md: Exemplos de código completos para todos os padrões de teste (Padrões 1-8 mais Lembretes)
- anti-patterns-and-reference.md: Anti-padrões, TestKit tradicional, integração CI/CD
Escolhendo sua Abordagem de Teste
Use Akka.Hosting.TestKit (Recomendado para 95% dos Casos)
Quando:
- Construir aplicações .NET modernas com
Microsoft.Extensions.DependencyInjection - Usar Akka.Hosting para configuração de atores em produção
- Precisar injetar serviços em atores (
IOptions,DbContext,ILogger, clientes HTTP, etc.) - Testar aplicações que usam ASP.NET Core, Worker Services ou .NET Aspire
- Trabalhar com projetos Akka.NET modernos (Akka.NET v1.5+)
Vantagens:
- Suporte nativo a injeção de dependência - substitua serviços por fakes nos testes
- Paridade de configuração com produção (os mesmos métodos de extensão funcionam nos testes)
- Separação limpa entre lógica do ator e infraestrutura
- Registro de atores tip-safe para recuperação de atores
Use Akka.TestKit Tradicional
Quando:
- Contribuir para o desenvolvimento da biblioteca principal do Akka.NET
- Trabalhar em ambientes sem
Microsoft.Extensions(aplicações console, sistemas legados) - Bases de código legadas que usam criação manual de
Propssem DI
Consulte anti-patterns-and-reference.md para padrões do TestKit tradicional.
Princípios Fundamentais (Akka.Hosting.TestKit)
- Herdar de
Akka.Hosting.TestKit.TestKit- Esta é uma classe base do framework, não uma classe definida pelo usuário - Sobrescrever
ConfigureServices()- Substitua serviços reais por fakes/mocks - Sobrescrever
ConfigureAkka()- Configure atores usando os mesmos métodos de extensão da produção - Usar
ActorRegistry- Recuperação tip-safe de referências de atores - Composição sobre Herança - Serviços fake como campos, não classes base
- Sem Classes Base Personalizadas - Use sobrescritas de métodos, não hierarquias de herança
- Teste um Ator por Vez - Use TestProbes para dependências
- Corresponder aos Padrões de Produção - Mesmos métodos de extensão,
AkkaExecutionModediferente
Pacotes NuGet Necessários
<ItemGroup>
<!-- Framework de teste principal -->
<PackageReference Include="Akka.Hosting.TestKit" Version="*" />
<!-- xUnit (ou seu framework de teste preferido) -->
<PackageReference Include="xunit" Version="*" />
<PackageReference Include="xunit.runner.visualstudio" Version="*" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="*" />
<!-- Asserções (recomendado) -->
<PackageReference Include="FluentAssertions" Version="*" />
<!-- Persistência em memória para testes -->
<PackageReference Include="Akka.Persistence.Hosting" Version="*" />
<!-- Se testar cluster sharding -->
<PackageReference Include="Akka.Cluster.Hosting" Version="*" />
</ItemGroup>
CRÍTICO: Correção do File Watcher para Projetos de Teste
O Akka.Hosting.TestKit cria instâncias reais de IHost, que por padrão habilitam observadores de arquivo para recarga de configuração. Ao executar muitos testes, isso esgota os limites de descritores de arquivo no Linux (limite de observação inotify).
Adicione isso ao seu projeto de teste - ele é executado antes de qualquer teste:
// TestEnvironmentInitializer.cs
using System.Runtime.CompilerServices;
namespace YourApp.Tests;
internal static class TestEnvironmentInitializer
{
[ModuleInitializer]
internal static void Initialize()
{
// Desabilita a observação de arquivos de configuração nos hosts de teste
// Previne o esgotamento de descritores de arquivo (limite de observação inotify) no Linux
Environment.SetEnvironmentVariable("DOTNET_HOSTBUILDER__RELOADCONFIGONCHANGE", "false");
}
}
Por que isso é importante:
[ModuleInitializer]é executado automaticamente antes de qualquer código de teste- Define a variável de ambiente globalmente para todas as instâncias de
IHost - Previne erros obscuros de
inotifyao executar 100+ testes - Também se aplica a testes de integração com Aspire que usam
IHost
Visão Geral dos Padrões de Teste
Cada padrão abaixo tem uma descrição resumida. Consulte examples.md para exemplos de código completos.
Padrão 1: Teste Básico de Ator
O padrão fundamental. Sobrescreva ConfigureServices() para injetar fakes, sobrescreva ConfigureAkka() para registrar atores com os mesmos métodos de extensão da produção.
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);
}
}
Padrão 2: TestProbe para Interações entre Atores
Registre um TestProbe no ActorRegistry como substituto para um ator de dependência. Use ExpectMsgAsync<T>() para verificar se as mensagens foram enviadas.
Padrão 3: TestProbe com Resposta Automática
Quando o ator sob teste usa Ask para se comunicar com dependências, crie um ator de resposta automática que encaminha mensagens para uma sonda E responde para evitar timeouts.
Padrão 4: Teste de Atores Persistentes
Use WithInMemoryJournal() e WithInMemorySnapshotStore(). Teste a recuperação matando o ator com PoisonPill e consultando para forçar a recuperação do journal.
Padrão 5: Reutilizar Configuração de Produção
Sempre reutilize os métodos de extensão da produção nos testes em vez de duplicar a configuração HOCON. Isso garante que os testes usem exatamente a mesma configuração da produção.
protected override void ConfigureAkka(AkkaConfigurationBuilder builder, IServiceProvider provider)
{
builder
.AddDraftSerializer() // Mesmo da produção
.AddOrderDomainActors(AkkaExecutionMode.LocalTest) // Mesmo, mas modo local
.WithInMemoryJournal().WithInMemorySnapshotStore(); // Substituições específicas de teste
}
Padrão 6: Cluster Sharding Localmente
Use AkkaExecutionMode.LocalTest com GenericChildPerEntityParent para testar o comportamento de sharding sem um cluster real. Mesmos métodos de extensão, modo diferente.
Padrão 7: AwaitAssertAsync para Operações Assíncronas
Use AwaitAssertAsync quando atores realizam operações assíncronas. Ele tenta novamente as asserções até que passem ou atinjam o timeout, prevenindo testes instáveis.
await AwaitAssertAsync(() =>
{
_fakeReadModelService.SyncCallCount.Should().BeGreaterOrEqualTo(1);
}, TimeSpan.FromSeconds(3));
Padrão 8: Testes de Integração Baseados em Cenários
Teste fluxos de trabalho de negócio completos de ponta a ponta com múltiplos atores e transições de estado. Registre todos os atores do domínio, verifique o estado em cada etapa.
Resumo dos Padrões Comuns
| Padrão | Caso de Uso |
|---|---|
| Teste Básico de Ator | Ator único com serviços injetados |
| TestProbe | Verificar se o ator envia mensagens para dependências |
| Respondedor Automático | Evitar timeouts de Ask durante testes |
| Ator Persistente | Testar event sourcing e recuperação |
| Cluster Sharding | Testar comportamento de sharding localmente |
| AwaitAssertAsync | Lidar com operações assíncronas em atores |
| Testes de Cenário | Fluxos de trabalho de negócio completos |
Melhores Práticas
- Uma classe de teste por ator - Mantenha os testes focados
- Sobrescreva ConfigureServices/ConfigureAkka - Não crie classes base
- Use fakes, não mocks - Mais simples, mais fáceis de manter
- Teste um ator por vez - Use TestProbes para dependências
- Corresponda aos padrões de produção - Mesmos métodos de extensão,
AkkaExecutionModediferente - Use AwaitAssertAsync para operações assíncronas - Previne testes instáveis
- Teste a recuperação - Mate e reinicie atores para verificar persistência
- Testes de cenário para fluxos de trabalho - Teste fluxos completos de negócio ponta a ponta
- Mantenha os testes rápidos - Persistência em memória, sem bancos de dados reais
- Use nomes significativos -
Scenario_FirstTimePurchase_SuccessfulPayment
Dicas de Depuração
- Ative logging de depuração - Passe
LogLevel.Debugpara o construtor do TestKit - Use ITestOutputHelper - Veja logs do sistema de atores na saída do teste
- Inspecione o TestProbe - Verifique
probe.Messagespara ver o que foi enviado - Consulte o estado do ator - Adicione mensagens de consulta de estado para depuração
- Use AwaitAssertAsync com logging - Veja por que as asserções falham
- Verifique o ActorRegistry - Confirme se os atores estão registrados corretamente
// Construtor com logging de depuração
public OrderActorTests(ITestOutputHelper output)
: base(output: output, logLevel: LogLevel.Debug)
{
}