다음을 통해 공유


Orleans을 사용한 단위 테스트

이 자습서에서는 조직이 올바르게 작동하는지 확인하기 위해 단위 테스트를 하는 방법을 보여 줍니다. 조직을 단위 테스트하는 두 가지 주요 방법이 있으며 선택하는 방법은 테스트하는 기능 형식에 따라 달라집니다. Microsoft.Orleans.TestingHost NuGet 패키지를 사용하여 조직에 대한 테스트 사일로를 만들거나 Moq와 같은 모의 프레임워크를 사용하여 조직이 상호 작용하는 Orleans 런타임의 일부를 모의할 수 있습니다.

TestCluster 사용

Microsoft.Orleans.TestingHost NuGet 패키지에는 기본적으로 두 개의 사일로로 구성된 메모리 내 클러스터를 만드는 데 사용할 수 있는 TestCluster가 포함되어 있으며, 이는 조직을 테스트하는 데 사용할 수 있습니다.

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은 모든 테스트가 완료되고 메모리 내 클러스터 사일로가 중지될 때 ClusterFixture 형식의 Dispose() 메서드를 호출합니다. TestCluster에는 클러스터에서 사일로를 구성하는 데 사용할 수 있는 TestClusterOptions를 허용하는 생성자도 있습니다.

사일로에서 종속성 주입을 사용하여 조직에서 서비스를 사용할 수 있도록 하는 경우 다음 패턴도 사용할 수 있습니다.

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 속성이지만 대부분의 모의 프레임워크에서 모의할 수 있으려면 속성이 publicvirtual이어야 합니다. 따라서 가장 먼저 GrainFactorypublicvirtual 속성으로 만들어야 합니다.

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을 만듭니다. 즉, 모의된 IJournalGrain을 반환할 수 있도록 GrainFactory의 동작을 재정의할 수 있습니다. 그런 다음, WorkerGrain이 예상대로 IJournalGrain와 상호 작용하는지 확인할 수 있습니다.