Aracılığıyla paylaş


Birim testi

Birim testleri iş mantığını doğrular ve regresyonlara karşı koruma sağlar. Kalıcı düzenlemeler birden çok etkinliği koordine eder ve hızla karmaşıklaşabilir. Birim testleri eklemek hataları erken yakalamanıza yardımcı olur.

Durable Functions ile orkestratörleri, etkinlikleri ve istemci (tetikleyici) işlevlerini çerçeve tarafından sağlanan bağlam nesnelerini taklit ederek ve işlevlerinizi doğrudan çağırarak test edebilirsiniz. Bu yaklaşım, iş mantığınızı Azure Functions çalışma zamanından ayırır.

Tek başına Dayanıklı Görev SDK'ları, harici bağımlılıklar olmadan bellek içinde düzenleme çalıştıran yerleşik test altyapısı sağlar. Orkestratörleri ve aktiviteleri bir test çalışanına kaydeder, bir test istemcisi aracılığıyla orkestrasyonları zamanlar ve sonuçları doğrularsınız. C# ve JavaScript için mock kütüphaneleri gerekmez. Python sahte geçmiş olaylarıyla yürütücü tabanlı bir yaklaşım kullanır.

Önkoşullar

  • xUnit — test çerçevesi
  • Microsoft.DurableTask.InProcessTestHost NuGet paketi

Düzenleyici işlevlerini test edin

Orchestrator işlevleri etkinlikleri, zamanlayıcıları ve dış olayları koordine eder. Bunlar genellikle en çok iş mantığını içerir ve birim testinden en iyi şekilde yararlanırlar.

Etkinlik çağrılarının dönüş değerlerini denetlemek için orkestrasyon bağlamını simüle edin. Ardından orchestrator'ınızı doğrudan çağırın ve çıkışı doğrulayın.

Bir etkinliği üç kez çağıran bu düzenleyiciyi göz önünde bulundurun:

[Function(nameof(HelloCitiesOrchestration))]
public static async Task<List<string>> HelloCities(
    [OrchestrationTrigger] TaskOrchestrationContext context)
{
    var outputs = new List<string>
    {
        await context.CallActivityAsync<string>(nameof(SayHello), "Tokyo"),
        await context.CallActivityAsync<string>(nameof(SayHello), "Seattle"),
        await context.CallActivityAsync<string>(nameof(SayHello), "London")
    };

    return outputs;
}

Her etkinlik çağrısı için beklenen dönüş değerlerini taklit TaskOrchestrationContext etmek ve ayarlamak için Moq kullanın:

[Fact]
public async Task HelloCities_ReturnsExpectedGreetings()
{
    var contextMock = new Mock<TaskOrchestrationContext>();

    contextMock.Setup(x => x.CallActivityAsync<string>(
        It.Is<TaskName>(n => n.Name == nameof(SayHello)),
        It.Is<string>(n => n == "Tokyo"),
        It.IsAny<TaskOptions>())).ReturnsAsync("Hello Tokyo!");

    contextMock.Setup(x => x.CallActivityAsync<string>(
        It.Is<TaskName>(n => n.Name == nameof(SayHello)),
        It.Is<string>(n => n == "Seattle"),
        It.IsAny<TaskOptions>())).ReturnsAsync("Hello Seattle!");

    contextMock.Setup(x => x.CallActivityAsync<string>(
        It.Is<TaskName>(n => n.Name == nameof(SayHello)),
        It.Is<string>(n => n == "London"),
        It.IsAny<TaskOptions>())).ReturnsAsync("Hello London!");

    var result = await HelloCitiesOrchestration.HelloCities(contextMock.Object);

    Assert.Equal(3, result.Count);
    Assert.Equal("Hello Tokyo!", result[0]);
    Assert.Equal("Hello Seattle!", result[1]);
    Assert.Equal("Hello London!", result[2]);
}

Bellek içinde orkestrasyonları çalıştırmak için DurableTaskTestHost kullanın. Üretim orkestratörünüzü ve etkinlik sınıflarınızı kaydedin, bir orkestrasyon zamanlayın ve sonucu doğrulayın.

Bu üretim sınıflarını göz önünde bulundurarak:

class HelloCitiesOrchestrator : TaskOrchestrator<string, List<string>>
{
    public override async Task<List<string>> RunAsync(
        TaskOrchestrationContext context, string input)
    {
        var outputs = new List<string>
        {
            await context.CallActivityAsync<string>(nameof(SayHelloActivity), "Tokyo"),
            await context.CallActivityAsync<string>(nameof(SayHelloActivity), "Seattle"),
            await context.CallActivityAsync<string>(nameof(SayHelloActivity), "London")
        };
        return outputs;
    }
}

class SayHelloActivity : TaskActivity<string, string>
{
    public override Task<string> RunAsync(TaskActivityContext context, string name)
    {
        return Task.FromResult($"Hello {name}!");
    }
}

Bunları doğrudan test konağına kaydedin:

[Fact]
public async Task HelloCities_ReturnsExpectedGreetings()
{
    await using var host = await DurableTaskTestHost.StartAsync(tasks =>
    {
        tasks.AddOrchestrator<HelloCitiesOrchestrator>();
        tasks.AddActivity<SayHelloActivity>();
    });

    string instanceId = await host.Client.ScheduleNewOrchestrationInstanceAsync(
        nameof(HelloCitiesOrchestrator));
    OrchestrationMetadata result = await host.Client.WaitForInstanceCompletionAsync(
        instanceId, getInputsAndOutputs: true);

    Assert.Equal(OrchestrationRuntimeStatus.Completed, result.RuntimeStatus);

    var output = result.ReadOutputAs<List<string>>();
    Assert.Equal(3, output.Count);
    Assert.Equal("Hello Tokyo!", output[0]);
    Assert.Equal("Hello Seattle!", output[1]);
    Assert.Equal("Hello London!", output[2]);
}

DurableTaskTestHost tam bir bellek içi orkestrasyon motoru çalıştırır. Dış hizmetler veya yan araç süreçleri gerekmez.

Test etkinliği işlevleri

Etkinlik işlevleri, API'leri çağırma, verileri işleme veya dış sistemlerle etkileşim kurma gibi gerçek çalışmayı içerir. Çerçeveye özgü yeniden yürütme davranışı olmadığından test etmek için en basit işlev türüdür.

Azure Functions'daki etkinlik işlevleri bir giriş alır ve isteğe bağlı bir FunctionContext içerir. Bunları diğer işlevler gibi test edin:

[Function(nameof(SayHello))]
public static string SayHello(
    [ActivityTrigger] string name, FunctionContext executionContext)
{
    return $"Hello {name}!";
}
[Fact]
public void SayHello_ReturnsExpectedGreeting()
{
    var result = HelloCitiesOrchestration.SayHello("Tokyo", Mock.Of<FunctionContext>());
    Assert.Equal("Hello Tokyo!", result);
}

Etkinlik işlevleri bir bağlam nesnesi ve giriş alır. Bağlam düzenleme kimliği ve görev kimliği gibi meta veriler sağlar, ancak çoğu test buna ihtiyaç duymaz.

Orchestrator örneğindeki SayHelloActivity sınıfını kullanarak, RunAsync'i sahte bir bağlam ile doğrudan çağırın.

[Fact]
public async Task SayHello_ReturnsExpectedGreeting()
{
    var activity = new SayHelloActivity();
    var contextMock = new Mock<TaskActivityContext>();

    var result = await activity.RunAsync(contextMock.Object, "Tokyo");

    Assert.Equal("Hello Tokyo!", result);
}

DurableTaskTestHost kullandığınızda, etkinlikler orkestrasyon testinin bir parçası olarak da çalıştırılır. Etkinliğin karmaşık mantığı olmadığı sürece ayrı etkinlik testlerine ihtiyacınız yoktur.

İstemci işlevlerini test et

İstemci işlevleri (tetikleyici işlevleri olarak da adlandırılır) orkestrasyonları başlatır ve örnekleri yönetir. Orkestrasyon motoruyla etkileşime geçmek için dayanıklı istemci bağlantısını kullanırlar.

Bir orkestrasyonu başlatan bu HTTP tetikleyicisini göz önünde bulundurun:

[Function("HelloCitiesOrchestration_HttpStart")]
public static async Task<HttpResponseData> HttpStart(
    [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequestData req,
    [DurableClient] DurableTaskClient client,
    FunctionContext executionContext)
{
    string instanceId = await client.ScheduleNewOrchestrationInstanceAsync(
        nameof(HelloCitiesOrchestration));
    return await client.CreateCheckStatusResponseAsync(req, instanceId);
}

Bilinir bir örnek kimliği döndürmesi için DurableTaskClient nesnesini taklit et:

[Fact]
public async Task HttpStart_ReturnsAccepted()
{
    var durableClientMock = new Mock<DurableTaskClient>("testClient");
    var functionContextMock = new Mock<FunctionContext>();
    var instanceId = "test-instance-id";

    durableClientMock
        .Setup(x => x.ScheduleNewOrchestrationInstanceAsync(
            It.IsAny<TaskName>(),
            It.IsAny<object>(),
            It.IsAny<StartOrchestrationOptions>(),
            It.IsAny<CancellationToken>()))
        .ReturnsAsync(instanceId);

    var mockRequest = CreateMockHttpRequest(functionContextMock.Object);

    var responseMock = new Mock<HttpResponseData>(functionContextMock.Object);
    responseMock.SetupGet(r => r.StatusCode).Returns(HttpStatusCode.Accepted);

    durableClientMock
        .Setup(x => x.CreateCheckStatusResponseAsync(
            It.IsAny<HttpRequestData>(),
            It.IsAny<string>(),
            It.IsAny<CancellationToken>()))
        .ReturnsAsync(responseMock.Object);

    var result = await HelloCitiesOrchestration.HttpStart(
        mockRequest, durableClientMock.Object, functionContextMock.Object);

    Assert.Equal(HttpStatusCode.Accepted, result.StatusCode);
}