إنشاء اختبارات الوحدة من تشغيل سير العمل القياسي في Azure Logic Apps باستخدام Visual Studio Code

ينطبق على: Azure Logic Apps (قياسي)

اختبار الوحدة هو ممارسة أساسية تحافظ على التطبيق أو الحل الخاص بك موثوقا ودقيقا طوال دورة حياة تطوير البرامج. تساعدك اختبارات الوحدة على التحقق بكفاءة وبشكل منهجي من صحة المكونات الرئيسية في الحل الخاص بك.

بالنسبة إلى مهام سير عمل تطبيق المنطق القياسي، يمكنك إنشاء اختبارات الوحدة باستخدام Visual Studio Code وملحق Azure Logic Apps (Standard). تتيح لك هذه الإمكانية استخدام عمليات تشغيل سير العمل التي تم تنفيذها مسبقا لإنشاء اختبارات الوحدة وتخصيصها للسيناريوهات التي يدعمها حل تطبيق المنطق الخاص بك. يوفر هذا الأسلوب المزايا التالية:

  • إعادة استخدام تشغيل سير العمل لإنشاء بيانات وهمية لعمليات معينة في سير العمل.

    تتيح لك هذه البيانات اختبار مهام سير العمل دون الحاجة إلى استدعاء الخدمات الخارجية أو الأنظمة أو واجهات برمجة التطبيقات. يمكنك توفير الوقت، ويبقى سير العمل الخاص بك متوافقا مع سيناريو تنفيذ سير العمل الفعلي.

  • تحسين جودة سير العمل عن طريق تحديد المشكلات المحتملة ومعالجتها قبل النشر في بيئات أخرى.

  • تبسيط تكامل اختبار الوحدة مع عملية التطوير الخاصة بك، مع ضمان سلوك سير عمل متسق ودقيق.

يوضح هذا الدليل كيفية إنشاء تعريف اختبار وحدة من تشغيل سير العمل. يستهزئ هذا التعريف بالمكالمات الخارجية من كل عملية سير عمل دون تغيير منطق سير العمل. عند إنشاء اختبار وحدة من تشغيل سير عمل، تحصل على مشروع اختبار وحدة يتضمن مجلدين:

  • مجلد يحتوي على فئات مكتوبة بقوة لكل عملية قابلة للنسخ في سير العمل.

  • مجلد لكل تعريف اختبار وحدة، والذي يتضمن الملفات التالية:

    • ملف JSON يمثل العمليات المقلدة التي تم إنشاؤها في سير العمل الخاص بك.

    • ملف C# الذي يحتوي على نموذج فئة وأساليب تستخدمها لإعداد التأكيدات الخاصة بك، تأكد من أن سير العمل يتصرف كما هو متوقع، وتأكد من أن سير العمل يتصرف بشكل موثوق ومتوقع في نظام Azure البنائي الأكبر.

المتطلبات الأساسية

القيود والمشاكل المعروفة

  • يدعم هذا الإصدار حاليا C# فقط لإنشاء اختبارات الوحدة.

  • لا يدعم هذا الإصدار الإجراءات غير المقلدة. تأكد من أن جميع الإجراءات في مسار تنفيذ سير العمل هي نسخة وهمية.

  • لا يدعم هذا الإصدار أنواع الإجراءات التالية:

    • إجراءات حساب التكامل
    • إجراءات Data Mapper
    • إجراءات التعليمات البرمجية المخصصة
    • إجراءات XML
    • الإجراءات السائلة
    • إجراءات ترميز وفك ترميز EDI

مراجعة المفاهيم الأساسية

تتضمن القائمة التالية مفاهيم أساسية ولكنها مهمة حول اختبارات الوحدة لسير العمل القياسي:

  • اختبار وحدة تطبيق المنطق

    تنفيذ سير عمل يتم التحكم فيه الذي يقوم بإدخال كائنات وهمية. تمثل هذه الكائنات إما مشغل سير العمل أو الإجراءات التي تعتمد على الخدمات الخارجية أو الأنظمة.

  • إجراء قابل للزخرية

    إجراء سير عمل يعتمد على خدمة أو نظام خارجي. يمكنك تحويل هذه الإجراءات إلى إجراءات وهمية لإنشاء اختبار الوحدة وتنفيذها.

إنشاء اختبار وحدة من تشغيل سير عمل

  1. في Visual Studio Code، افتح مشروع تطبيق المنطق القياسي.

  2. في شريط أدوات Visual Studio Code، من قائمة Run ، حدد Start Debugging. (لوحة المفاتيح: اضغط على F5)

  3. ارجع إلى نافذة المستكشف . في مشروعك، قم بتوسيع مجلد تعريف سير العمل.

  4. افتح القائمة المختصرة workflow.json ، وحدد نظرة عامة.

  5. في صفحة النظرة العامة، ضمن Run history، حدد تشغيل سير العمل لاستخدامه لإنشاء اختبار وحدة.

    تظهر لقطة الشاشة Visual Studio Code مع مشروع تطبيق المنطق القياسي، ووضع تتبع الأخطاء قيد التشغيل، وصفحة نظرة عامة على سير العمل المفتوح، وتشغيل سير العمل المحدد.

  6. في شريط أدوات محفوظات التشغيل، حدد إنشاء اختبار وحدة من التشغيل.

    تظهر لقطة الشاشة Visual Studio Code وصفحة محفوظات تشغيل سير العمل القياسي والأمر المحدد لإنشاء اختبار الوحدة.

  7. أدخل اسما لاستخدامه لاختبار الوحدة وفئة اختبار الوحدة وملف C#‎.

    في نافذة Explorer ، يظهر مجلد مشروع جديد يسمى Tests ضمن مجلد مشروع logic app. يحتوي مجلد الاختبارات على المجلدات والملفات التالية:

    تظهر لقطة الشاشة Visual Studio Code ومشروع تطبيق المنطق القياسي ومجلد الاختبارات مع مجلدات وملفات اختبار الوحدة.

    مجلد أو ملف ‏‏الوصف
    Tests
    || <logic-app-name>
    في Tests المجلد، <logic-app-name> يظهر مجلد عند إضافة اختبارات الوحدة إلى مشروع تطبيق منطقي.
    Tests
    || <logic-app-name>
    ||| <workflow-name>
    في <logic-app-name> المجلد، <workflow-name> يظهر مجلد عند إضافة اختبارات وحدة لسير عمل.
    Tests
    || <logic-app-name>
    ||| <workflow-name>
    |||| MockOutputs
    < operation-name-outputs >||||| .cs
    في <workflow-name> المجلد، MockOutputs يحتوي المجلد على ملف C# (.cs) مع فئات مكتوبة بقوة لكل عملية موصل في سير العمل. يستخدم كل اسم ملف .cs التنسيق التالي:

    < operation-name >[Trigger\|Action]Output.cs

    إذا كانت عملية الموصل تحتوي على عقود ديناميكية، تظهر فئة لكل نوع ديناميكي. يشير النوع الديناميكي إلى معلمة عملية لها مدخلات ومخرجات مختلفة استنادا إلى القيمة المقدمة لتلك المعلمة. يمكنك استخدام هذه الفئات لتوسيع اختبارات الوحدة وإنشاء نماذج جديدة من البداية.
    Tests
    || <logic-app-name>
    ||| <workflow-name>
    |||| <unit-test-name>
    ||||| <unit-test-name>-mock.json
    ||||| <unit-test-name>.cs
    في <workflow-name> المجلد، <unit-test-name> يحتوي المجلد على الملفات التالية:

    <unit-test-name>-mock.json- يحتوي الملف على تمثيل JSON للرسائل الوهمية التي تم إنشاؤها، استنادا إلى تشغيل سير العمل الذي أنشأ اختبار الوحدة.

    <unit-test-name>.cs- يحتوي الملف على نموذج فئة C# والأساليب التي تستخدم *-mock.json الملف لتشغيل النتائج وتأكيدها. يمكنك تحرير هذا الملف لمطابقة سيناريوهات الاختبار المحددة.

مراجعة ملف *-mock.json

يحتوي هذا الملف على الأقسام الرئيسية التالية:

triggerMocks قسم

triggerMocks يحتوي القسم على النتيجة المقلدة من مشغل سير العمل. هذا القسم مطلوب لبدء تنفيذ سير العمل كما هو موضح في المثال التالي:

{
    "triggerMocks": {
        "When_messages_are_available_in_a_queue_(peek-lock)": {
            "name": "When_messages_are_available_in_a_queue_(peek-lock)",
            "status": "Succeeded",
            "outputs": {
                "body": {
                    "contentData": {
                        "messageId": "1234",
                        "status": "new",
                        "contentType": "application/json",
                        "userProperties": {},
                        "scheduledEnqueueTimeUtc": "1/1/0001 12:00:00 AM",
                        "timeToLive": "14.00:00:00",
                        "deliveryCount": 1,
                        "enqueuedSequenceNumber": 0,
                        "enqueuedTimeUtc": "2025-04-07T01:10:09.738Z",
                        "lockedUntilUtc": "2025-04-07T01:11:09.769Z",
                        "lockToken": "78232fa8-03cf-4baf-b1db-3375a64e0ced",
                        "sequenceNumber": 5
                    }
                }
            }
        }
    },
    "actionMocks": {...}
}

actionMocks قسم

لكل إجراء قابل للاحتواء في تشغيل سير العمل، actionMocks يحتوي القسم على إجراء وهمي ويضمن التنفيذ الخاضع للرقابة لسير العمل.

{
    "triggerMocks": {...},
    "actionMocks": {
        "Call_External_API": {
            "name": "Call_External_API",
            "status": "Succeeded",
            "outputs": {
                "statusCode": 200,
                "body": {
                    "status": "Awesome!"
                }
            }
        },
        "CompleteMessage": {
            "name": "CompleteMessage",
            "status": "Succeeded",
            "outputs": {
                "statusCode": "OK",
                "body": {}
            }
        }
    }
}

مراجعة ملف *.cs اختبار الوحدة

توفر فئة اختبار الوحدة هذه إطار عمل لاختبار مهام سير عمل تطبيق المنطق القياسي عن طريق تقليد المشغلات والإجراءات. تتيح لك هذه الفئة اختبار مهام سير العمل دون استدعاء الخدمات الخارجية أو واجهات برمجة التطبيقات بالفعل.

اختبار بنية الفئة

تستخدم فئة اختبار الوحدة النموذجية البنية التالية:

[TestClass]
public class <unit-test-name>
{
    public TestExecutor TestExecutor;

    [TestInitialize]
    public void Setup()
    {
        this.TestExecutor = new TestExecutor("<workflow-name>/testSettings.config");
    }

    // Add test methods here.

    // Add helper methods here.
}

أسلوب Setup()

يقوم هذا الأسلوب بإنشاء مثيل للفئة TestExecutor باستخدام المسار إلى ملف تكوين إعدادات الاختبار. يتم تشغيل الأسلوب قبل كل تنفيذ اختبار وإنشاء مثيل جديد من TestExecutor.

[TestInitialize]
public void Setup()
{
    this.TestExecutor = new TestExecutor("<workflow-name>/testSettings.config");
}

نموذج أساليب الاختبار

يصف القسم التالي نماذج أساليب الاختبار التي يمكنك استخدامها في فئة اختبار الوحدة.

اختبار البيانات الوهمية الثابتة

يوضح الأسلوب التالي كيفية استخدام البيانات الوهمية الثابتة لاختبار سير العمل. في هذا الأسلوب، يمكنك إكمال المهام التالية:

  • تعيين قيم الخصائص على الإجراءات الوهمية.
  • تنفيذ سير العمل باستخدام البيانات الوهمية المكونة.
  • تأكد من نجاح التنفيذ.
[TestMethod]
public async Task <workflow-name>_<unit-test-name>_ExecuteWorkflow_SUCCESS_Sample1()
{
    // PREPARE mock: Generate mock action and trigger data.
    var mockData = this.GetTestMockDefinition();
    var sampleActionMock = mockData.ActionMocks["Call_External_API"];
    sampleActionMock.Outputs["your-property-name"] = "your-property-value";

    // ACT: Create the UnitTestExecutor instance. Run the workflow with mock data.
    var testRun = await this.TestExecutor
        .Create()
        .RunWorkflowAsync(testMock: mockData).ConfigureAwait(continueOnCapturedContext: false);

    // ASSERT: Confirm successful workflow execution and that the status is 'Succeeded'.
    Assert.IsNotNull(value: testRun);
    Assert.AreEqual(expected: TestWorkflowStatus.Succeeded, actual: testRun.Status);
}

اختبار البيانات الوهمية الديناميكية

يوضح الأسلوب التالي كيفية استخدام البيانات الوهمية الديناميكية مع أساليب رد الاتصال. يمنحك هذا الأسلوب خيارين يولدان بيانات وهمية ديناميكيا:

يتيح لك كلا النهجين إنشاء استجابات ديناميكية استنادا إلى سياق تنفيذ اختبار الوحدة.

[TestMethod]
public async Task <workflow-name>_<unit-test-name>_ExecuteWorkflow_SUCCESS_Sample2()
{
    // PREPARE: Generate mock action and trigger data.
    var mockData = this.GetTestMockDefinition();
    
    // OPTION 1: Define a callback class.
    mockData.ActionMocks["Call_External_API"] = new CallExternalAPIActionMock(
        name: "Call_External_API", 
        onGetActionMock: CallExternalAPIActionMockOutputCallback);

    // OPTION 2: Define an inline lambda function.
    mockData.ActionMocks["Call_External_API"] = new CallExternalAPIActionMock(
        name: "Call_External_API", 
        onGetActionMock: (testExecutionContext) =>
        {
            return new CallExternalAPIActionMock(
                status: TestWorkflowStatus.Succeeded,
                outputs: new CallExternalAPIActionOutput {

                    // If this account contains a JObject Body, 
                    // set the properties you want here:
                    // Body = "something".ToJObject()

                }
            );
        });
        
    // ACT: Create UnitTestExecutor instance. Run the workflow with mock data.
    var testRun = await this.TestExecutor
        .Create()
        .RunWorkflowAsync(testMock: mockData).ConfigureAwait(continueOnCapturedContext: false);

    // ASSERT: Confirm successful workflow execution and that the status is 'Succeeded'.
    Assert.IsNotNull(value: testRun);
    Assert.AreEqual(expected: TestWorkflowStatus.Succeeded, actual: testRun.Status);
}

اختبار سيناريو الخطأ

يوضح الأسلوب التالي كيفية اختبار شروط الفشل. في هذا الأسلوب، يمكنك إكمال المهام التالية:

  • تكوين الإجراءات المقلدة للفشل مع رموز ورسائل خطأ محددة.
  • تأكد من أن سير العمل يعالج حالات الخطأ هذه بشكل صحيح.
[TestMethod]
public async Task <workflow-name>_<unit-test-name>_ExecuteWorkflow_FAILED_Sample3()
{
    // PREPARE: Generate mock action and trigger data.
    var mockData = this.GetTestMockDefinition();
    var mockError = new TestErrorInfo(code: ErrorResponseCode.BadRequest, message: "Input is invalid.");
    mockData.ActionMocks["Call_External_API"] = new CallExternalAPIActionMock(
        status: TestWorkflowStatus.Failed, 
        error: mockError);

    // ACT: Create UnitTestExecutor instance. Run the workflow with mock data.
    var testRun = await this.TestExecutor
        .Create()
        .RunWorkflowAsync(testMock: mockData).ConfigureAwait(continueOnCapturedContext: false);

    // ASSERT: Confirm successful workflow execution and that the status is 'Succeeded'.
    Assert.IsNotNull(value: testRun);
    Assert.AreEqual(expected: TestWorkflowStatus.Failed, actual: testRun.Status);
}

طرق المساعد

يصف القسم التالي الأساليب المستخدمة من قبل نماذج أساليب الاختبار. تظهر أساليب المساعد ضمن أساليب الاختبار في تعريف الفئة.

GetTestMockDefinition()

يقوم الأسلوب التالي بتحميل التعريف الوهمي من ملف JSON. يمكنك تحرير هذا الأسلوب إذا تم تخزين البيانات الوهمية في موقع أو تنسيق مختلف.

private TestMockDefinition GetTestMockDefinition()
{
    var mockDataPath = Path.Combine(TestExecutor.rootDirectory, "Tests", TestExecutor.logicAppName, 
        TestExecutor.workflow, "<unit-test-name>", "<unit-test-name>-mock.json");
    return JsonConvert.DeserializeObject<TestMockDefinition>(File.ReadAllText(mockDataPath));
}

طريقة رد الاتصال

ينشئ الأسلوب التالي بيانات وهمية ديناميكيا. يختلف اسم الأسلوب استنادا إلى اسم الإجراء الوهمي في أساليب الاختبار للبيانات الوهمية الثابتة أو الديناميكية. يمكنك تحرير هذا الأسلوب لإرجاع استجابات وهمية مختلفة استنادا إلى متطلبات سيناريو الاختبار أو استخدامه كقالب لإنشاء أساليب رد الاتصال الديناميكية الخاصة بك.

public CallExternalAPIActionMock CallExternalAPIActionMockOutputCallback(TestExecutionContext context)
{
    // Sample mock data: Dynamically change the mocked data for "actionName".
    return new CallExternalAPIActionMock(
        status: TestWorkflowStatus.Succeeded,
        outputs: new CallExternalAPIActionOutput {

            // If this account contains a JObject Body, 
            // set the properties you want here:
            // Body = "something".ToJObject()

        }
    );
}