Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Met unit tests voor duurzame orkestraties kunt u de bedrijfslogica verifiëren en fouten vroegtijdig opsporen. Indelingen coördineren meerdere activiteiten en kunnen snel complex worden, dus tests beschermen tegen regressies naarmate uw werkstroom zich ontwikkelt.
Selecteer het tabblad dat overeenkomt met uw project: Durable Functions als u Azure Functions gebruikt of Urable Task SDK's als u de zelfstandige SDK zonder Azure Functions gebruikt.
Met Durable Functions test je orchestrators, activiteiten en clientfuncties (triggers) door de door het framework geleverde contextobjecten te simuleren en je functies direct aan te roepen. Deze benadering isoleert uw bedrijfslogica van de Azure Functions runtime.
Hier volgt een minimale C#-orchestratortest om het patroon weer te geven:
[Fact]
public async Task MyOrchestrator_CallsActivity()
{
var contextMock = new Mock<TaskOrchestrationContext>();
contextMock.Setup(x => x.CallActivityAsync<string>(
It.IsAny<TaskName>(), It.IsAny<string>(), It.IsAny<TaskOptions>()))
.ReturnsAsync("result");
var result = await MyOrchestrator.Run(contextMock.Object);
Assert.Equal("result", result);
}
In de rest van dit artikel wordt dit patroon uitgebreid beschreven voor C# en Python.
De zelfstandige Durable Task SDK's bieden een ingebouwde testinfrastructuur waarmee indelingen in het geheugen worden uitgevoerd zonder externe afhankelijkheden. U registreert orchestrators en activiteiten bij een testmedewerker, plant indelingen via een testclient en bevestigt de resultaten. Er is geen mocking vereist voor C# en JavaScript. Python maakt gebruik van een op generator gebaseerde benadering met handmatige resultaatinjectie.
Hier volgt een minimale C#-test om het patroon weer te geven:
[Fact]
public async Task MyOrchestrator_Completes()
{
await using var host = await DurableTaskTestHost.StartAsync(tasks =>
{
tasks.AddOrchestrator<MyOrchestrator>();
tasks.AddActivity<MyActivity>();
});
string id = await host.Client.ScheduleNewOrchestrationInstanceAsync(nameof(MyOrchestrator));
var result = await host.Client.WaitForInstanceCompletionAsync(id, getInputsAndOutputs: true);
Assert.Equal(OrchestrationRuntimeStatus.Completed, result.RuntimeStatus);
}
In de rest van dit artikel wordt dit patroon uitgebreid beschreven voor C#, Python en JavaScript.
Vereiste voorwaarden
- xUnit — testframework
- Moq — framework voor mocken (simuleren van softwarecomponenten)
- Bekendheid met het .NET geïsoleerd werkermodel
- xUnit — testframework
- Het
Microsoft.DurableTask.InProcessTestHostNuGet-pakket (v1.0.0 of hoger)
Het testen van de orchestratorfunctionaliteit
Orchestrator-functies coördineren activiteiten, timers en externe gebeurtenissen. Ze bevatten doorgaans de meeste bedrijfslogica en profiteren het meeste van eenheidstests.
Simuleer de orkestratiecontext om de retourwaarden van activiteitsoproepen te besturen. Roep vervolgens uw orchestrator rechtstreeks aan en controleer de uitvoer.
Houd rekening met deze orchestrator die drie keer een activiteit aanroept:
[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;
}
Gebruik Moq om TaskOrchestrationContext te mocken en verwachte retourwaarden in te stellen voor elke activiteitsoproep.
Note
Het It.Is<TaskName>(...) patroon is vereist omdat CallActivityAsync een TaskName struct accepteert, geen gewone tekenreeks. Moq heeft een expliciete typematch nodig.
[Fact]
public async Task HelloCities_ReturnsExpectedGreetings()
{
var contextMock = new Mock<TaskOrchestrationContext>();
// Mock each activity call to return a known value
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]);
}
Gebruik DurableTaskTestHost om orkestraties in het geheugen uit te voeren. Registreer uw productie-orchestrator- en activiteitsklassen, plan een orkestratie en valideer het resultaat.
Gezien deze productieklassen:
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}!");
}
}
Registreer ze rechtstreeks in de testhost:
[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 voert een complete in-memory orkestratie-engine uit. Er zijn geen externe services of sidecar-processen vereist.
Testactiviteitsfuncties
Activiteitsfuncties bevatten de werkelijke hoeveelheid werk, het aanroepen van API's, het verwerken van gegevens of het werken met externe systemen. Ze zijn het eenvoudigste functietype om te testen omdat ze geen frameworkspecifiek herhalingsgedrag hebben.
Activiteitsfuncties in Azure Functions ontvangen een invoer en eventueel een FunctionContext. Test ze net als elke andere functie:
[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);
}
Activiteitsfuncties ontvangen een contextobject en invoer. De context biedt metagegevens zoals de indelings-id en taak-id, maar de meeste tests hebben deze niet nodig.
Gebruik de SayHelloActivity-klasse uit het orchestrator-voorbeeld om RunAsync direct aan te roepen met een mock-context:
[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);
}
Wanneer u DurableTaskTestHost gebruikt, worden activiteiten ook uitgevoerd als onderdeel van de orkestratietest. U hebt geen afzonderlijke activiteitstests nodig, tenzij de activiteit complexe logica heeft.
Testen van clientfuncties
Clientfuncties (ook wel triggerfuncties genoemd) starten orkestraties en beheren instanties. Ze gebruiken de duurzame clientbinding om te communiceren met de orchestration-engine.
Overweeg deze HTTP-trigger die een orchestratie start:
[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);
}
Mock DurableTaskClient om een bekende instance-ID te retourneren:
[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);
}
Clientbewerkingen testen
Met de standalone Durable Task SDK's gebruiken clientbewerkingen (orchestraties plannen, status opvragen, gebeurtenissen afhandelen) hetzelfde TestOrchestrationClient als in de orchestratortests. Er bestaat geen afzonderlijke clientfunctie. U roept de client-API rechtstreeks aan.
DurableTaskTestHost introduceert host.Client, wat een volledig functioneel DurableTaskClient is. Gebruik deze om bewerkingen op clientniveau te testen, zoals inplannen, het uitvoeren van query's of beëindigen van orkestraties.
[Fact]
public async Task Client_CanQueryOrchestrationStatus()
{
await using var host = await DurableTaskTestHost.StartAsync(tasks =>
{
tasks.AddOrchestrator<HelloCitiesOrchestrator>();
tasks.AddActivity<SayHelloActivity>();
});
string instanceId = await host.Client.ScheduleNewOrchestrationInstanceAsync(
nameof(HelloCitiesOrchestrator));
// Query status while the orchestration runs
OrchestrationMetadata metadata = await host.Client.WaitForInstanceCompletionAsync(
instanceId, getInputsAndOutputs: true);
Assert.Equal(OrchestrationRuntimeStatus.Completed, metadata.RuntimeStatus);
Assert.Equal(instanceId, metadata.InstanceId);
}