Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Tutorial ini menunjukkan cara unit menguji biji-bijian Anda untuk memastikannya berperilaku dengan benar. Ada dua cara utama untuk menyatukan pengujian biji-bijian Anda, dan metode yang Anda pilih tergantung pada jenis fungsionalitas yang Anda uji. Gunakan paket Microsoft.Orleans.TestingHost NuGet untuk membuat silo pengujian untuk grain Anda, atau gunakan kerangka kerja tiruan seperti Moq untuk membuat tiruan bagian dari Orleans runtime yang berinteraksi dengan grain Anda.
Gunakan InProcessTestCluster (disarankan)
InProcessTestCluster adalah infrastruktur pengujian yang direkomendasikan untuk Orleans. Ini menyediakan API berbasis delegasi yang efisien untuk mengonfigurasi kluster pengujian, sehingga lebih mudah untuk berbagi layanan antara pengujian Anda dan kluster.
Keuntungan utama
Keuntungan utama dari InProcessTestCluster lebih TestCluster adalah ergonomi:
- Konfigurasi berbasis delegasi: Mengonfigurasi silo dan klien menggunakan delegasi sebaris alih-alih kelas konfigurasi terpisah
- Instans layanan bersama: Berbagi layanan tiruan, pengujian ganda, dan instans lainnya dengan mudah antara kode pengujian Anda dan host silo
-
Mengurangi kode boilerplate: Tidak perlu membuat kelas terpisah
ISiloConfiguratoratauIClientConfigurator - Injeksi dependensi yang lebih sederhana: Mendaftarkan layanan langsung di API fluent builder
Baik InProcessTestCluster dan TestCluster gunakan host silo dalam proses yang mendasar yang sama secara default, sehingga penggunaan memori dan waktu startup setara.
TestCluster API dirancang untuk juga mendukung skenario multi-proses (untuk simulasi seperti produksi), yang memerlukan pendekatan konfigurasi berbasis kelas, tetapi secara default berjalan dalam proses seperti InProcessTestCluster.
Penggunaan dasar
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);
}
}
Mengonfigurasi kluster pengujian
Gunakan InProcessTestClusterBuilder untuk mengonfigurasi silo, klien, dan layanan:
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
| Option | Tipe | Bawaan | Description |
|---|---|---|---|
| ClusterId | string |
Dibuat secara otomatis | Pengidentifikasi kluster. |
| ServiceId | string |
Dibuat secara otomatis | Pengidentifikasi layanan. |
InitialSilosCount |
int |
1 | Jumlah silo yang akan dipersiapkan di awal. |
InitializeClientOnDeploy |
bool |
true |
Apakah akan menginisialisasi klien secara otomatis saat disebarkan. |
ConfigureFileLogging |
bool |
true |
Aktifkan pengelogan file untuk pemecahan masalah. |
UseRealEnvironmentStatistics |
bool |
false |
Gunakan statistik memori/CPU nyata alih-alih nilai yang disimulasikan. |
GatewayPerSilo |
bool |
true |
Apakah setiap silo menghosting gateway untuk koneksi klien. |
Berbagi kluster pengujian di antara pengujian
Untuk meningkatkan performa pengujian, bagikan satu kluster di beberapa kasus pengujian menggunakan perlengkapan 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);
}
}
Menambahkan dan menghapus silo selama pengujian
InProcessTestCluster memungkinkan pengelolaan silo dinamis untuk menguji perilaku kluster.
// 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();
Gunakan TestCluster
TestCluster menggunakan pendekatan konfigurasi berbasis kelas yang memerlukan penerapan antarmuka ISiloConfigurator dan IClientConfigurator. Desain ini mendukung skenario pengujian multi-proses di mana silo berjalan dalam proses terpisah, yang berguna untuk pengujian simulasi seperti produksi. Namun, secara default TestCluster juga berjalan dalam proses dengan performa yang setara dengan InProcessTestCluster.
Pilih TestCluster di atas InProcessTestCluster ketika:
- Anda memerlukan pengujian multi-proses untuk simulasi produksi
- Anda memiliki pengujian yang ada menggunakan
TestClusterAPI - Anda memerlukan kompatibilitas dengan Orleans 7.x atau 8.x
Untuk pengujian baru, InProcessTestCluster disarankan karena konfigurasi berbasis delegasi yang lebih sederhana.
Paket Microsoft.Orleans.TestingHost NuGet berisi TestCluster, yang dapat Anda gunakan untuk membuat kluster dalam memori (terdiri dari dua silo secara default) untuk menguji butir.
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);
}
}
Karena overhead memulai kluster dalam memori, Anda mungkin ingin membuat TestCluster dan menggunakannya kembali di antara beberapa kasus pengujian. Misalnya, capai ini menggunakan kelas xUnit atau perlengkapan koleksi.
Untuk membagikan TestCluster di antara beberapa kasus pengujian, pertama-tama buat tipe fixture:
using Orleans.TestingHost;
public sealed class ClusterFixture : IDisposable
{
public TestCluster Cluster { get; } = new TestClusterBuilder().Build();
public ClusterFixture() => Cluster.Deploy();
void IDisposable.Dispose() => Cluster.StopAllSilos();
}
Selanjutnya, buat perlengkapan koleksi:
[CollectionDefinition(Name)]
public sealed class ClusterCollection : ICollectionFixture<ClusterFixture>
{
public const string Name = nameof(ClusterCollection);
}
Sekarang Anda dapat menggunakan TestCluster kembali dalam kasus pengujian Anda:
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);
}
}
Ketika semua pengujian selesai dan silo kluster dalam memori berhenti, xUnit memanggil metode dari tipe Dispose().
TestCluster juga memiliki konstruktor yang menerima TestClusterOptions yang dapat Anda gunakan untuk mengonfigurasi silo di kluster.
Jika Anda menggunakan Injeksi Dependensi di Silo Anda untuk membuat layanan tersedia untuk Biji-bijian, Anda juga dapat menggunakan pola ini:
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>(/* ... */);
}
}
Menggunakan tiruan
Orleans juga memungkinkan mengejek banyak bagian sistem. Untuk banyak skenario, ini adalah cara term mudah untuk menyatukan biji-bijian pengujian. Pendekatan ini memiliki batasan (misalnya, seputar penjadwalan reentransi dan serialisasi) dan mungkin memerlukan grains untuk menyertakan kode yang hanya digunakan dalam tes unit Anda. Orleans TestKit menyediakan pendekatan alternatif yang menghindari banyak batasan ini.
Misalnya, bayangkan biji-bijian yang Anda uji berinteraksi dengan biji-bijian lain. Untuk memperagakan atau menggandakan biji-bijian lainnya, Anda juga perlu menggandakan anggota GrainFactory dari biji-bijian yang sedang diuji. Secara default, GrainFactory adalah properti protected normal, tetapi sebagian besar kerangka kerja mocking memerlukan properti untuk menjadi public dan virtual agar dapat di-mock. Jadi, langkah pertama adalah membuat GrainFactory dan publicvirtual:
public new virtual IGrainFactory GrainFactory
{
get => base.GrainFactory;
}
Sekarang Anda dapat membuat instance Anda di luar runtime Orleans dan menggunakan mock untuk mengontrol perilaku 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());
}
}
Di sini, buat biji-bijian di bawah pengujian, WorkerGrain, menggunakan Moq. Ini memungkinkan perubahan perilaku GrainFactory sehingga mengembalikan simulasi IJournalGrain. Anda kemudian dapat memverifikasi bahwa WorkerGrain berinteraksi dengan IJournalGrain seperti yang diharapkan.