このチュートリアルでは、グレインを単体テストして、正しく動作することを確認する方法について説明します。 グレインを単体テストする主な方法は 2 つあります。選択する方法は、テストする機能の種類によって異なります。 Microsoft.Orleans.TestingHost NuGet パッケージを使用して、グレインのテストサイロを作成するか、Moq などのモックフレームワークを使用して、グレインが対話するOrleansランタイムの一部をモックします。
TestCluster
を使用してください。
Microsoft.Orleans.TestingHost
NuGet パッケージにはTestClusterが含まれています。これは、グレインをテストするためのメモリ内クラスター (既定では 2 つのサイロで構成) を作成するために使用できます。
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);
}
}
メモリ内クラスターの起動に伴うオーバーヘッドがあるため、TestCluster
を作成して複数のテストケースで再利用することをお勧めします。 たとえば、xUnit のクラスまたはコレクションフィクスチャを使用してこれを実現します。
複数のテスト ケース間で TestCluster
を共有するには、まずフィクスチャタイプを作成します。
using Orleans.TestingHost;
public sealed class ClusterFixture : IDisposable
{
public TestCluster Cluster { get; } = new TestClusterBuilder().Build();
public ClusterFixture() => Cluster.Deploy();
void IDisposable.Dispose() => Cluster.StopAllSilos();
}
次に、コレクションフィクスチャを作成します。
[CollectionDefinition(Name)]
public sealed class ClusterCollection : ICollectionFixture<ClusterFixture>
{
public const string Name = nameof(ClusterCollection);
}
テスト ケースで 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);
}
}
すべてのテストが完了し、メモリ内クラスター サイロが停止すると、xUnit はDispose()の種類のClusterFixture
メソッドを呼び出します。
TestCluster
には、クラスター内のサイロの構成に使用できる TestClusterOptions を受け入れるコンストラクターもあります。
サイロで依存性注入を用いてサービスをGrainsで利用可能にする場合、このパターンも使用できます。
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)
{
siloBuilder.ConfigureServices(static services =>
{
// TODO: Call required service registrations here.
// services.AddSingleton<T, Impl>(/* ... */);
});
}
}
モックを使用する
Orleans また、システムの多くの部分をモックすることができます。 多くのシナリオでは、これは、グレインを単体テストする最も簡単な方法です。 この方法には限界があります(たとえば、再入可能性とシリアル化に関するスケジュール設定など)で、単体テストでのみ使用されるコードを含める必要がある場合があります。 Orleans TestKit には、これらの制限の多くを回避する代替アプローチが用意されています。
たとえば、テストしているグレインが他のグレインと対話するとします。 これらの他のグレインをモックするには、テスト対象のグレインの GrainFactory メンバーをモックする必要もあります。 既定では、GrainFactory
は通常のprotected
プロパティですが、ほとんどのモックフレームワークでは、モックを可能にするためにプロパティをpublic
し、virtual
にする必要があります。 そのため、最初の手順は、GrainFactory
とpublic
の両方virtual
することです。
public new virtual IGrainFactory GrainFactory
{
get => base.GrainFactory;
}
これで、 Orleans ランタイムの外部にグレインを作成し、モックを使用して 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());
}
}
ここでは、Moq を使用して、テスト対象のグレイン WorkerGrain
作成します。 これにより、 GrainFactory
の動作をオーバーライドして、モックされた IJournalGrain
を返すことができます。 その後、 WorkerGrain
が期待どおりに IJournalGrain
と対話することを確認できます。
.NET