Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
V tomto kurzu se dozvíte, jak zrna testovat, aby se zajistilo, že se chovají správně. Existují dva hlavní způsoby testování zrn a metoda, kterou zvolíte, závisí na typu funkce, kterou testujete. Použijte balíček NuGet Microsoft.Orleans.TestingHost k vytvoření testovacích sil pro vaše aktory nebo použijte napodobovací rámec, jako je Moq, k napodobení částí Orleans modulu runtime, se kterými váš aktor interaguje.
Použijte InProcessTestCluster (doporučeno)
Jedná se InProcessTestCluster o doporučenou testovací infrastrukturu pro Orleans. Poskytuje zjednodušené rozhraní API založené na delegátech pro konfiguraci testovacích clusterů, což usnadňuje sdílení služeb mezi testy a clusterem.
Klíčové výhody
Hlavní výhodou InProcessTestCluster oproti TestClusterergonomii je:
- Konfigurace založená na delegátech: Konfigurace sila a klientů využívajících vložené delegáty místo samostatných tříd konfigurace
- Instance sdílených služeb: Snadné sdílení napodobených služeb, testovacích dvojníků a dalších instancí mezi vaším testovacím kódem a silo hostiteli
-
Méně šablonového kódu: Není nutné vytvářet samostatné
ISiloConfiguratorneboIClientConfiguratortřídy - Jednodušší injektáž závislostí: Registrace služeb přímo v rozhraní FLUENT API tvůrce
InProcessTestCluster a TestCluster ve výchozím nastavení používají stejného základního hostitele sila v procesu, takže využití paměti a čas spuštění jsou stejné. Rozhraní TestCluster API je navržené tak, aby podporovalo také scénáře s více procesy (pro simulaci podobné produkčnímu prostředí), které vyžadují přístup konfigurace založený na třídě, ale ve výchozím nastavení se spouští v procesu stejně jako InProcessTestCluster.
Základní použití
using Orleans.TestingHost;
using Xunit;
public class HelloGrainTests : IAsyncLifetime
{
private InProcessTestCluster _cluster = null!;
public async Task InitializeAsync()
{
var builder = new InProcessTestClusterBuilder();
_cluster = builder.Build();
await _cluster.DeployAsync();
}
public async Task DisposeAsync()
{
await _cluster.DisposeAsync();
}
[Fact]
public async Task SaysHello()
{
var grain = _cluster.Client.GetGrain<IHelloGrain>(0);
var result = await grain.SayHello("World");
Assert.Equal("Hello, World!", result);
}
}
Konfigurace testovacího clusteru
Slouží InProcessTestClusterBuilder ke konfiguraci sila, klientů a služeb:
var builder = new InProcessTestClusterBuilder(initialSilosCount: 2);
// Configure silos
builder.ConfigureSilo((options, siloBuilder) =>
{
siloBuilder.AddMemoryGrainStorage("Default");
siloBuilder.AddMemoryGrainStorage("PubSubStore");
});
// Configure clients
builder.ConfigureClient(clientBuilder =>
{
// Client-specific configuration
});
// Configure both silos and clients (shared services)
builder.ConfigureHost(hostBuilder =>
{
hostBuilder.Services.AddSingleton<IMyService, MyService>();
});
var cluster = builder.Build();
await cluster.DeployAsync();
InProcessTestClusterOptions
| Možnost | Typ | Výchozí | Description |
|---|---|---|---|
| ClusterId | string |
Automaticky vygenerováno | Identifikátor clusteru. |
| ServiceId | string |
Automaticky vygenerováno | Identifikátor služby. |
InitialSilosCount |
int |
1 | Počet sil, která se mají zprovoznit nejprve. |
InitializeClientOnDeploy |
bool |
true |
Určuje, jestli se má automaticky inicializovat klient při nasazení. |
ConfigureFileLogging |
bool |
true |
Povolte protokolování souborů pro ladění. |
UseRealEnvironmentStatistics |
bool |
false |
Místo simulovaných hodnot používejte statistiku skutečné paměti a procesoru. |
GatewayPerSilo |
bool |
true |
Určuje, jestli každý silo hostuje bránu pro připojení klientů. |
Sdílení testovacího clusteru mezi testy
Pokud chcete zvýšit výkon testů, sdílejte jeden cluster napříč několika testovacími případy pomocí příslušenství xUnit:
public class ClusterFixture : IAsyncLifetime
{
public InProcessTestCluster Cluster { get; private set; } = null!;
public async Task InitializeAsync()
{
var builder = new InProcessTestClusterBuilder();
builder.ConfigureSilo((options, siloBuilder) =>
{
siloBuilder.AddMemoryGrainStorageAsDefault();
});
Cluster = builder.Build();
await Cluster.DeployAsync();
}
public async Task DisposeAsync()
{
await Cluster.DisposeAsync();
}
}
[CollectionDefinition(nameof(ClusterCollection))]
public class ClusterCollection : ICollectionFixture<ClusterFixture>
{
}
[Collection(nameof(ClusterCollection))]
public class HelloGrainTests
{
private readonly ClusterFixture _fixture;
public HelloGrainTests(ClusterFixture fixture)
{
_fixture = fixture;
}
[Fact]
public async Task SaysHello()
{
var grain = _fixture.Cluster.Client.GetGrain<IHelloGrain>(0);
var result = await grain.SayHello("World");
Assert.Equal("Hello, World!", result);
}
}
Přidat a odebrat úložiště během testů
Podpora InProcessTestCluster dynamického řízení úložných modulů pro testování fungování clusteru:
// Start with 2 silos
var builder = new InProcessTestClusterBuilder(initialSilosCount: 2);
var cluster = builder.Build();
await cluster.DeployAsync();
// Add a third silo
var newSilo = await cluster.StartSiloAsync();
// Stop a silo
await cluster.StopSiloAsync(newSilo);
// Restart all silos
await cluster.RestartAsync();
Použijte TestCluster
Používá TestCluster metodu konfigurace založenou na třídě, která vyžaduje implementaci ISiloConfigurator a IClientConfigurator rozhraní. Tento návrh podporuje testování víceprocesních scénářů, ve kterých sila běží v oddělených procesech, což je užitečné pro testování simulací podobných produkčnímu prostředí. Ve výchozím nastavení však TestCluster běží také v procesu s ekvivalentním výkonem jako InProcessTestCluster.
Zvolte TestCluster místo InProcessTestCluster kdy:
- Potřebujete víceprocesové testování pro produkční simulaci.
- Máte existující testy pomocí
TestClusterrozhraní API. - Potřebujete kompatibilitu s Orleans verzí 7.x nebo 8.x.
Pro nové testy se doporučuje InProcessTestCluster kvůli jednodušší konfiguraci založené na delegátech.
Balíček Microsoft.Orleans.TestingHost NuGet obsahuje TestCluster, který můžete použít k vytvoření clusteru v paměti (který se ve výchozím nastavení skládá ze dvou sila) pro testování zrn.
using Orleans.TestingHost;
namespace Tests;
public class HelloGrainTests
{
[Fact]
public async Task SaysHelloCorrectly()
{
var builder = new TestClusterBuilder();
var cluster = builder.Build();
cluster.Deploy();
var hello = cluster.GrainFactory.GetGrain<IHelloGrain>(Guid.NewGuid());
var greeting = await hello.SayHello("World");
cluster.StopAllSilos();
Assert.Equal("Hello, World!", greeting);
}
}
Kvůli režii při spouštění clusteru v paměti můžete chtít vytvořit TestCluster a znovu ho použít v několika testovacích případech. Dosáhnete toho například pomocí třídy xUnit nebo sběrných zařízení.
Pokud chcete sdílet TestCluster více testovacích případů, nejprve vytvořte typ zařízení:
using Orleans.TestingHost;
public sealed class ClusterFixture : IDisposable
{
public TestCluster Cluster { get; } = new TestClusterBuilder().Build();
public ClusterFixture() => Cluster.Deploy();
void IDisposable.Dispose() => Cluster.StopAllSilos();
}
Dále vytvořte zařízení kolekce:
[CollectionDefinition(Name)]
public sealed class ClusterCollection : ICollectionFixture<ClusterFixture>
{
public const string Name = nameof(ClusterCollection);
}
V testovacích případech teď můžete znovu použít TestCluster :
using Orleans.TestingHost;
namespace Tests;
[Collection(ClusterCollection.Name)]
public class HelloGrainTestsWithFixture(ClusterFixture fixture)
{
private readonly TestCluster _cluster = fixture.Cluster;
[Fact]
public async Task SaysHelloCorrectly()
{
var hello = _cluster.GrainFactory.GetGrain<IHelloGrain>(Guid.NewGuid());
var greeting = await hello.SayHello("World");
Assert.Equal("Hello, World!", greeting);
}
}
Po dokončení všech testů a zastavení paměťových silo clusteru xUnit volá Dispose() metodu ClusterFixture typu.
TestCluster má také konstruktor, který přijímá TestClusterOptions, který lze použít ke konfiguraci sil v clusteru.
Pokud v silu použijete injektáž závislostí k zpřístupnění služeb pro zrna, můžete použít i tento model:
using Microsoft.Extensions.DependencyInjection;
using Orleans.TestingHost;
namespace Tests;
public sealed class ClusterFixtureWithConfig : IDisposable
{
public TestCluster Cluster { get; } = new TestClusterBuilder()
.AddSiloBuilderConfigurator<TestSiloConfigurations>()
.Build();
public ClusterFixtureWithConfig() => Cluster.Deploy();
void IDisposable.Dispose() => Cluster.StopAllSilos();
}
file sealed class TestSiloConfigurations : ISiloConfigurator
{
public void Configure(ISiloBuilder siloBuilder)
{
// TODO: Call required service registrations here.
// siloBuilder.Services.AddSingleton<T, Impl>(/* ... */);
}
}
Použít mocky
Orleans umožňuje také mockování mnoha částí systému. V mnoha scénářích je to nejjednodušší způsob, jak testovat zrnka. Tento přístup má omezení (např. ohledně plánování reentrancy a serializace) a může vyžadovat zahrnutí kódu do zrnka používaného pouze jednotkovými testy. TestKitOrleans nabízí alternativní přístup, který omezuje řadu těchto omezení.
Představte si například zrnko, které testujete, komunikuje s jinými zrnky. Chcete-li napodobit tato ostatní zrna, musíte také napodobit GrainFactory člena zrna, které testujete. Ve výchozím nastavení GrainFactory je normální protected vlastnost, ale většina nástrojů pro vytváření mocků vyžaduje, aby vlastnosti byly public a virtual, aby bylo možné provádět napodobování. Prvním krokem je tedy provést GrainFactory obojí, tedy public i virtual:
public new virtual IGrainFactory GrainFactory
{
get => base.GrainFactory;
}
Teď můžete vytvořit svůj objekt mimo prostředí Orleans a pomocí mockování řídit chování GrainFactory.
using Xunit;
using Moq;
namespace Tests;
public class WorkerGrainTests
{
[Fact]
public async Task RecordsMessageInJournal()
{
var data = "Hello, World";
var journal = new Mock<IJournalGrain>();
var worker = new Mock<WorkerGrain>();
worker
.Setup(x => x.GrainFactory.GetGrain<IJournalGrain>(It.IsAny<Guid>()))
.Returns(journal.Object);
await worker.DoWork(data)
journal.Verify(x => x.Record(data), Times.Once());
}
}
Vytvořte zde zkušební objekt WorkerGrain pomocí Moq. To umožňuje přebití chování GrainFactory, aby vracelo mockovaný IJournalGrain. Pak můžete ověřit, že WorkerGrain komunikuje IJournalGrain podle očekávání.