إشعار
يتطلب الوصول إلى هذه الصفحة تخويلاً. يمكنك محاولة تسجيل الدخول أو تغيير الدلائل.
يتطلب الوصول إلى هذه الصفحة تخويلاً. يمكنك محاولة تغيير الدلائل.
اختبارات الوحدة تتحقق من منطق الأعمال وتحمي من الانحدارات. تنسق التوزيعات الموسيقية المتطورة أنشطة متعددة ويمكن أن تصبح معقدة بسرعة. إضافة اختبارات الوحدات تساعدك على اكتشاف الأخطاء مبكرا.
مع Durable Functions، تختبر المنسقين والأنشطة ودوال العميل (المحفز) عن طريق محاكاة كائنات السياق المقدمة من الإطار واستدعاء وظائفك مباشرة. هذا النهج يعزل منطق عملك عن وقت تشغيل Azure Functions.
توفر مجموعات تطوير المهام المستدامة المستقلة بنية تحتية اختبار مدمجة تشغل التنسيقات في الذاكرة دون تبعيات خارجية. تقوم بتسجيل المنسقين والأنشطة مع عامل اختبار، وتحدد جدولة التنسيقات من خلال عميل الاختبار، وتؤكد على النتائج. لا حاجة للمحاكاة في C# وJavaScript. تستخدم Python نهجا قائما على المنفذ مع أحداث تاريخ تجريبي.
المتطلبات الأساسية
- xUnit — إطار عمل اختبار
-
Microsoft.DurableTask.InProcessTestHostحزمة NuGet
وظائف التنسيق التجريبي
تنسق وظائف التنسيق الأنشطة والمؤقتات والأحداث الخارجية. عادة ما تحتوي على أكبر قدر من المنطق التجاري وتستفيد أكثر من اختبار الوحدات.
قم بمحاكاة سياق التنسيق للتحكم في قيم عودة استدعاءات النشاط. ثم اتصل بالمنسق الخاص بك مباشرة وتحقق من المخرج.
تخيل هذا المنسق الذي يستدعي نشاطا ثلاث مرات:
[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;
}
استخدم Moq لتحديد TaskOrchestrationContext وإعداد قيم العائد المتوقعة لكل استدعاء نشاط:
[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]);
}
يستخدم DurableTaskTestHost لتشغيل التوزيعات الموسيقية في الذاكرة. سجل دروس التنسيق والأنشطة الإنتاجية، وحدد موعدا للتوزيع الأوركسترالي، وأكد على النتيجة.
بالنظر إلى هذه الفئات الإنتاجية:
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}!");
}
}
سجلها مباشرة في مضيف الاختبار:
[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 يشغل محرك توزيع أوركسترالي كامل في الذاكرة. لا حاجة لخدمات خارجية أو عمليات جانبية.
دوال نشاط الاختبار
تحتوي دوال النشاط على العمل الفعلي — استدعاء واجهات برمجة التطبيقات (APIs)، معالجة البيانات، أو التفاعل مع الأنظمة الخارجية. هي أبسط نوع من الدوال للاختبار لأنها لا تملك سلوك إعادة تشغيل خاص بإطار العمل.
تستقبل دوال النشاط في Azure Functions مدخلا واختياريا FunctionContext. اختبرها مثل أي وظيفة أخرى:
[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);
}
تستقبل دوال النشاط كائن سياق ومدخل. يوفر السياق بيانات وصفية مثل معرف التوزيع ومعرف المهمة، لكن معظم الاختبارات لا تحتاجها.
باستخدام الفئة SayHelloActivity من مثال المنسق، اتصل RunAsync مباشرة مع سياق تجريبي:
[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، تشغل الأنشطة أيضا كجزء من اختبار التوزيع الموسيقي. لا تحتاج إلى اختبارات نشاط منفصلة إلا إذا كان النشاط منطقيا معقدا.
وظائف عميل الاختبار
تبدأ وظائف العميل (وتسمى أيضا وظائف المحفز) التنسيقات وتدير المثلات. يستخدمون الربط القوي للعميل للتفاعل مع محرك التوزيع الأوركسترالي.
فكر في هذا المشغل HTTP الذي يبدأ التوزيع الموسيقي:
[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);
}
محاكاة DurableTaskClient لإرجاع معرف مثيل معروف:
[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);
}
المحتوى ذو الصلة
- نظرة عامة Durable Functions
- قيود كود وظائف التنسيق