Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Las pruebas unitarias comprueban la lógica de negocios y protegen contra las regresiones. Las orquestaciones duraderas coordinan varias actividades y pueden volverse complejas rápidamente. Agregar pruebas unitarias le ayuda a detectar errores al principio.
Con Durable Functions, probarás las funciones de orquestadores, actividades y de cliente (desencadenador) mediante simular los objetos de contexto proporcionados por el marco y llamando directamente a las funciones. Este enfoque aísla la lógica de negocios del entorno de ejecución de Azure Functions.
Los SDK de Durable Task independientes proporcionan una infraestructura de prueba integrada que ejecuta orquestaciones en memoria sin dependencias externas. Puede registrar orquestadores y actividades con un trabajador de prueba, programar orquestaciones a través de un cliente de prueba y verificar los resultados. No se requiere ningún simulacro para C# y JavaScript. Python usa un enfoque basado en ejecutor con eventos de historial ficticios.
Prerrequisitos
- C#
- Python
- JavaScript
- xUnit : marco de pruebas
- El paquete NuGet
Probar las funciones del orquestador
Las funciones de Orquestador coordinan actividades, temporizadores y eventos externos. Normalmente contienen la mayor lógica de negocios y se benefician más de las pruebas unitarias.
Simular el contexto de orquestación para controlar los valores devueltos de las llamadas de actividad. A continuación, llame directamente al orquestador y compruebe la salida.
- C#
- Python
- JavaScript
Tenga en cuenta este orquestador que llama a una actividad tres veces:
[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;
}
Use Moq para simular y configurar los valores devueltos esperados para cada llamada de actividad:
[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]);
}
- C#
- Python
- JavaScript
Usar para ejecutar orquestaciones en la memoria. Registre sus clases de orquestador y actividad de producción, programe una orquestación y compruebe el resultado.
Dadas estas clases de producción:
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}!");
}
}
Regístrelos directamente en el host de prueba:
[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]);
}
ejecuta un motor de orquestación completo en memoria. No se requieren servicios externos ni procesos auxiliares.
Funciones de actividad de prueba
Las funciones de actividad contienen el trabajo real: llamar a las API, procesar datos o interactuar con sistemas externos. Son el tipo de función más sencillo que se va a probar porque no tienen ningún comportamiento de reproducción específico del marco.
- C#
- Python
- JavaScript
Las funciones de actividad de Azure Functions reciben una entrada y, opcionalmente, una FunctionContext. Pruóbelos como cualquier otra función:
[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);
}
Las funciones de actividad reciben un objeto de contexto y una entrada. El contexto proporciona metadatos como el identificador de orquestación y el identificador de tarea, pero la mayoría de las pruebas no lo necesitan.
- C#
- Python
- JavaScript
Con la clase del ejemplo del orquestador, llame directamente con un contexto ficticio:
[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);
}
Cuando utilizas , las actividades también se ejecutan como parte de la prueba de orquestación. No necesita pruebas de actividad independientes a menos que la actividad tenga lógica compleja.
Probar funciones de cliente
Las funciones cliente (también denominadas funciones de desencadenador) inician orquestaciones y administran instancias. Usan el enlace de cliente duradero para interactuar con el motor de orquestación.
- C#
- Python
- JavaScript
Tenga en cuenta este desencadenador HTTP que inicia una orquestación:
[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);
}
Simulación para devolver un identificador de instancia conocido:
[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);
}
Contenido relacionado
- Información general sobre Durable Functions
- Restricciones de código de función de Orchestrator
- ¿Qué es Durable Task?
- Restricciones de código de función de Orchestrator