Delen via


Eenheidstests met Orleans

In deze zelfstudie ziet u hoe u uw korrels test om ervoor te zorgen dat ze zich correct gedragen. Er zijn twee belangrijkste manieren om uw korrels te testen en de methode die u kiest, is afhankelijk van het type functionaliteit dat u test. De Microsoft.Orleans. TestingHost NuGet-pakket kan worden gebruikt om testsilo's voor uw korrels te maken, of u kunt een mocking-framework zoals Moq gebruiken om delen van de Orleans runtime te mocken waarmee uw graan communiceert.

Gebruik de TestCluster

Het Microsoft.Orleans.TestingHost NuGet-pakket bevat TestCluster dat kan worden gebruikt om een in-memory cluster te maken, dat standaard bestaat uit twee silo's, die kunnen worden gebruikt om korrels te testen.

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);
    }
}

Vanwege de overhead van het starten van een in-memory cluster, kunt u een TestCluster cluster maken en opnieuw gebruiken in meerdere testcases. Dit kan bijvoorbeeld worden gedaan met behulp van xUnit's klasse- of verzamelingsarmaturen.

Als u een TestCluster tussen meerdere testcases wilt delen, maakt u eerst een type armaturen:

using Orleans.TestingHost;

public sealed class ClusterFixture : IDisposable
{
    public TestCluster Cluster { get; } = new TestClusterBuilder().Build();

    public ClusterFixture() => Cluster.Deploy();

    void IDisposable.Dispose() => Cluster.StopAllSilos();
}

Maak vervolgens een verzamelingsarmaturen:

[CollectionDefinition(Name)]
public sealed class ClusterCollection : ICollectionFixture<ClusterFixture>
{
    public const string Name = nameof(ClusterCollection);
}

U kunt nu een TestCluster in uw testcases opnieuw gebruiken:

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 roept de Dispose() methode van het ClusterFixture type aan wanneer alle tests zijn voltooid en de in-memory clustersilo's worden gestopt. TestCluster heeft ook een constructor die accepteert TestClusterOptions dat kan worden gebruikt om de silo's in het cluster te configureren.

Als u afhankelijkheidsinjectie in uw silo gebruikt om services beschikbaar te maken voor Grains, kunt u dit patroon ook gebruiken:

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>(/* ... */);
        });
    }
}

Mocks gebruiken

Orleans maakt het ook mogelijk om veel onderdelen van het systeem te bespotten, en voor veel scenario's is dit de eenvoudigste manier om korrels te testen. Deze aanpak heeft beperkingen (bijvoorbeeld bij het plannen van reentrancy en serialisatie) en kan vereisen dat korrels code bevatten die alleen door uw eenheidstests wordt gebruikt. De Orleans TestKit biedt een alternatieve benadering, die veel van deze beperkingen side-steps biedt.

Stel dat het graan dat u test, communiceert met andere korrels. Als u deze andere korrels wilt kunnen bespotten, moet u ook het GrainFactory lid van het graan onder de test bespotten. GrainFactory Standaard is een normale protected eigenschap, maar voor de meeste mockingframeworks moeten eigenschappen worden public gebruikt en virtual moeten ze kunnen worden gesimuleerd. Het eerste wat u moet doen, is dus zowel een eigenschap als een public virtual eigenschap makenGrainFactory:

public new virtual IGrainFactory GrainFactory
{
    get => base.GrainFactory;
}

U kunt nu uw graan buiten de Orleans runtime maken en mocking gebruiken om het gedrag van 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());
    }
}

Hier maakt u het graan onder test, WorkerGrainmet moq, wat betekent dat u het gedrag van het GrainFactory gedrag kunt overschrijven zodat het een gesimuleerde retourneert IJournalGrain. Vervolgens kunt u controleren of de WorkerGrain interactie met de IJournalGrain verwachte bewerking wordt gebruikt.