دليل أبو عمر الشامل: تصميم إطار Automation Testing قابل للتوسّع للشركات الكبيرة

يا جماعة الخير، السلام عليكم ورحمة الله.

بتذكر أول شغل إلي في شركة برمجيات كبيرة، كنت متحمس كثير. استلمت مشروع ضخم، وكان فيه حوالي 500 اختبار مؤتمت (Automated Test). قلت في نفسي “ما شاء الله، شغل مرتب!”. بعد أسبوعين، طلبوا مني تغيير بسيط في واجهة المستخدم: تغيير الـ ID تبع زر تسجيل الدخول. قلت بسيطة، شغلة دقيقتين. فتحت الكود لأغير السطر… وتفاجأت بالكارثة.

الـ ID تبع الزر كان مكتوب بشكل مباشر (Hardcoded) في أكثر من 100 ملف اختبار! قضيت يومين كاملين، مش بكتب كود جديد، لا، بس بصلّح كود قديم بسبب تغيير بسيط. يومها حلفت يمين إني ما أرجع أشتغل بهالطريقة العشوائية. هاي التجربة علمتني درس قاسي عن أهمية بناء إطار عمل (Framework) صح، قابل للتوسّع والصيانة. ومن يومها، صار هالموضوع خبزتي اليومية.

في هالمقالة، راح أشارككم خبرتي، “الزبدة” زي ما بنحكي، في كيفية تصميم إطار عمل لاختبارات الأتمتة يكون مرن وقوي ويتحمل ضغط الشغل في الشركات الكبيرة.

لماذا نحتاج لإطار عمل قابل للتوسّع؟

ممكن حدا يسأل، “ليش وجعة الراس هاي يا أبو عمر؟ خلص بكتب الاختبار وبمشي”. الجواب بسيط: اللي بيمشي اليوم، بكرا بوقّفك. بدون إطار عمل مصمم صح، راح توقع في مشاكل بتكبر مع الوقت زي كرة الثلج:

  • الكود الهش (Brittle Tests): أي تغيير صغير في واجهة المستخدم بيكسر عشرات الاختبارات.
  • تكرار الكود (Code Duplication): بتلاقي حالك بتكتب نفس الخطوات (زي تسجيل الدخول) في كل اختبار.
  • صعوبة الصيانة: لما بدك تعدل خطوة معينة، لازم تلف على كل الملفات وتعدلها، زي ما صار معي بالضبط.
  • بطء التطوير: كتابة اختبار جديد بتصير مهمة صعبة وبتاخذ وقت طويل لأنك بتبني كل شي من الصفر.
  • صعوبة القراءة: الاختبار بصير عبارة عن خليط من لوجيك البزنس وتفاصيل تقنية (زي الـ locators والـ waits)، وهالشي بخلّي فهمه صعب على أي حدا جديد في الفريق.

بالمقابل، إطار العمل المصمم جيدًا بيعطيك القوة والمرونة لتجنب كل هالمشاكل، وبخلي عملية الأتمتة أصلب وأكثر فعالية.

أساسيات التصميم: الفصل بين المسؤوليات (Separation of Concerns)

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

  1. طبقة الاختبار (Test Layer): هاي الطبقة هي اللي بتحكي “القصة”. بتوصف سيناريو الاختبار بلغة قريبة من لغة البزنس. مثال: “افتح صفحة تسجيل الدخول، أدخل اسم المستخدم وكلمة المرور، اضغط على زر الدخول، وتأكد من ظهور رسالة الترحيب”. هاي الطبقة ما بتهتم كيف بنضغط على الزر أو كيف بنلاقي حقل اسم المستخدم.
  2. طبقة منطق التطبيق (Application Logic Layer): هاي الطبقة هي المترجم. بتاخذ الأوامر عالية المستوى من طبقة الاختبار (مثل “سجّل الدخول”) وبتحولها لخطوات عملية على التطبيق. هنا بنستخدم أنماط تصميم مثل Page Object Model أو Screenplay Pattern.
  3. طبقة البنية التحتية (Infrastructure Layer): هاي الطبقة هي “العتّال” اللي بيعمل الشغل الثقيل في الخلفية. هي المسؤولة عن تشغيل المتصفح، التعامل مع الدرايفرات (ChromeDriver, GeckoDriver)، أخذ لقطات شاشة عند الفشل، قراءة ملفات الإعدادات، والاتصال بقواعد البيانات. طبقة الاختبار واللوجيك ما لازم يعرفوا أي شي عن هاي التفاصيل.

هذا الفصل هو اللي بيعطينا المرونة. لو قررنا نغير أداة الأتمتة من Selenium لـ Playwright، بنعدل فقط في طبقة البنية التحتية، وكل اختباراتنا بتضلها شغالة زي ما هي.

أنماط التصميم الشهيرة (Popular Design Patterns)

عشان نطبق مبدأ الفصل بين المسؤوليات، بنستخدم أنماط تصميم مجرّبة أثبتت فعاليتها. أشهر نمطين في عالم أتمتة الواجهات الرسومية هما Page Object Model و Screenplay Pattern.

نموذج كائن الصفحة (Page Object Model – POM)

هذا هو النمط الأشهر والأكثر استخدامًا، وهو نقطة بداية ممتازة. الفكرة بسيطة جدًا: كل صفحة في تطبيقك بنمثلها بـ Class خاص فيها في الكود.

هذا الـ Class بيحتوي على شغلتين أساسيتين:

  1. مُحدِّدات العناصر (Locators): تعريف لكل العناصر التفاعلية في الصفحة (أزرار، حقول إدخال، روابط…) باستخدام (ID, CSS Selector, XPath, etc).
  2. الدوال (Methods): دوال بتمثل الإجراءات اللي ممكن المستخدم يعملها على هاي الصفحة.

نصيحة من أبو عمر: لا تعمل دوال بتمثل أكشن واحد فقط (مثل `clickLoginButton`). الأفضل تعمل دوال بتمثل هدف أو مهمة للمستخدم (مثل `performLogin(username, password)`). هاي الدالة بداخلها بتقوم بإدخال اسم المستخدم، كلمة المرور، والضغط على الزر. هيك بصير كود الاختبار مقروء أكثر.

مثال عملي باستخدام Java و Selenium

لنفترض عنا صفحة تسجيل دخول بسيطة. بدون POM، ممكن الاختبار يكون هيك:

// Bad Practice: Everything in one test method
@Test
public void testSuccessfulLogin() {
    // Infrastructure code
    WebDriver driver = new ChromeDriver();
    driver.get("https://example.com/login");

    // Locators and Actions mixed with test logic
    WebElement usernameField = driver.findElement(By.id("username"));
    usernameField.sendKeys("abu_omar");

    WebElement passwordField = driver.findElement(By.id("password"));
    passwordField.sendKeys("secret_password");

    driver.findElement(By.id("login-btn")).click();

    // Assertion
    WebElement welcomeMessage = driver.findElement(By.cssSelector("h1.welcome"));
    Assert.assertTrue(welcomeMessage.getText().contains("أهلاً بك يا أبو عمر"));

    // Infrastructure code
    driver.quit();
}

هذا الكود “سباغيتي” بمعنى الكلمة. أي تغيير في الـ locators راح يجبرنا نعدل ملف الاختبار نفسه. الآن شوف كيف بصير أرتب مع POM:

1. ننشئ Class لصفحة تسجيل الدخول (LoginPage.java):

public class LoginPage {
    private WebDriver driver;

    // 1. Locators
    private By usernameField = By.id("username");
    private By passwordField = By.id("password");
    private By loginButton = By.id("login-btn");

    public LoginPage(WebDriver driver) {
        this.driver = driver;
    }

    // 2. Actions / Methods representing user goals
    public void enterUsername(String username) {
        driver.findElement(usernameField).sendKeys(username);
    }

    public void enterPassword(String password) {
        driver.findElement(passwordField).sendKeys(password);
    }

    public void clickLoginButton() {
        driver.findElement(loginButton).click();
    }

    // High-level business method
    public HomePage performLogin(String username, String password) {
        enterUsername(username);
        enterPassword(password);
        clickLoginButton();
        return new HomePage(driver); // Return the next page object
    }
}

2. الآن، ملف الاختبار بصير نظيف ومقروء:

public class LoginTests extends BaseTest { // BaseTest handles driver setup/teardown

    @Test
    public void testSuccessfulLogin() {
        LoginPage loginPage = new LoginPage(driver);
        
        // Test logic is now clean and readable
        HomePage homePage = loginPage.performLogin("abu_omar", "secret_password");
        
        // Assertion
        String welcomeText = homePage.getWelcomeMessage();
        Assert.assertTrue(welcomeText.contains("أهلاً بك يا أبو عمر"));
    }
}

شفت الفرق؟ الآن لو تغير الـ ID تبع زر الدخول، بنعدله في مكان واحد فقط: `LoginPage.java`. الاختبارات نفسها ما بتتغير. هذا هو جوهر الصيانة السهلة.

نمط السيناريو (Screenplay Pattern)

هذا النمط هو تطور لـ POM، وبيركز أكثر على سلوك المستخدم (User Behavior). هو مستوحى من مبادئ الـ Behavior-Driven Development (BDD). بيوصف الاختبارات من منظور “مَن” يقوم بالفعل، “ماذا” يمكنه أن يفعل، و”ما هي” أهدافه.

المكونات الأساسية لنمط السيناريو هي:

  • Actors (الممثلون): مين اللي بيستخدم النظام؟ (مثال: `Admin`, `Customer`).
  • Abilities (القدرات): شو بيقدر الممثل يعمل؟ (مثال: `BrowseTheWeb` باستخدام Selenium).
  • Tasks (المهام): أهداف عالية المستوى مكونة من عدة خطوات (مثال: `LoginToApplication`).
  • Interactions (التفاعلات): إجراءات منخفضة المستوى (مثال: `Click`, `EnterText`).
  • Questions (الأسئلة): للتأكد من حالة النظام (الـ Assertions).

كود الاختبار بصير يشبه اللغة الإنجليزية (أو العربية لو استخدمنا مكتبات تدعمها)، وبيكون مقروء جدًا حتى لغير المبرمجين.

مثال على شكل الاختبار باستخدام Screenplay (بشكل مفاهيمي):

// Conceptual Screenplay Test
@Test
public void testSuccessfulLogin() {
    Actor omar = Actor.named("Omar");
    omar.can(BrowseTheWeb.with(driver)); // Give the actor an ability

    omar.attemptsTo(
        // This is a Task
        Login.withCredentials("abu_omar", "secret_password") 
    );

    omar.should(
        // This is a Question
        seeThat(TheWelcomeMessage.text(), containsString("أهلاً بك"))
    );
}

نمط السيناريو قوي جدًا في المشاريع الضخمة والمعقدة، لأنه بيشجع على إعادة استخدام السلوكيات (Tasks and Interactions) بشكل كبير وبيخلي الاختبارات وثائق حية للنظام.

أفضل الممارسات (Best Practices) من الميدان

بعد ما تختار النمط المناسب، فيه شوية نصايح عملية بتفرق كثير في جودة إطار العمل تبعك:

1. إدارة البيانات (Data Management)

لا تكتب بيانات الاختبار (مثل أسماء المستخدمين، كلمات المرور، بيانات المنتجات) بشكل مباشر في الكود. افصلها في ملفات خارجية مثل JSON, YAML, أو حتى Excel. هذا بيسمحلك:

  • إعادة استخدام نفس الاختبار ببيانات مختلفة.
  • تعديل بيانات الاختبار بدون لمس الكود.
  • إمكانية مشاركة بيانات الاختبار مع فريق الـ Manual Testers.

2. التسجيل والتقارير (Logging and Reporting)

من أول يوم، ادمج مكتبة تقارير قوية مثل Allure Framework أو ExtentReports. تقرير جيد هو منقذك وقت الفشل. لازم التقرير يحتوي على:

  • خطوات الاختبار بالتفصيل.
  • لقطة شاشة (Screenshot) عند حدوث أي خطأ.
  • رسالة الخطأ الواضحة والـ Stack Trace.
  • الوقت اللي استغرقه كل اختبار.

3. التكوين المركزي (Centralized Configuration)

لا تكتب الـ URLs أو نوع المتصفح أو أي إعدادات أخرى بشكل مباشر في الكود. استخدم ملف إعدادات واحد (`config.properties` أو `config.yaml`) لكل هاي المتغيرات. هذا بيسهل عليك تشغيل نفس الاختبارات على بيئات مختلفة (Development, Staging, Production) بمجرد تغيير ملف الإعدادات.

4. التعامل الذكي مع الانتظار (Handling Waits)

العدو اللدود للاختبارات المستقرة هو `Thread.sleep()`. تجنبه تمامًا! استخدامه بيخلي اختباراتك بطيئة وغير موثوقة. بدلًا من ذلك، استخدم دائمًا آليات الانتظار الذكية (Smart Waits):

  • Explicit Wait: بتخلي الدرايفر ينتظر لحد ما يتحقق شرط معين (مثل ظهور عنصر، أو إمكانية الضغط عليه). هذا هو الخيار الأفضل والأكثر استقرارًا.
  • Fluent Wait: نسخة متقدمة من الـ Explicit Wait بتعطيك مرونة أكبر، مثل تجاهل أنواع معينة من الأخطاء أثناء الانتظار.

الخلاصة: إطار العمل كائن حي 🧠

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

  • افصل المسؤوليات: خلّي طبقة الاختبار تحكي القصة، وطبقة اللوجيك تنفذها، وطبقة البنية التحتية تعمل الشغل الثقيل.
  • اختر النمط المناسب: ابدأ بـ Page Object Model لأنه بسيط وفعال. إذا كبر مشروعك كثير، فكر بالانتقال لـ Screenplay Pattern.
  • اتبع أفضل الممارسات: اهتم بالبيانات، التقارير، الإعدادات، والتعامل الذكي مع الانتظار.

وأهم نصيحة من أخوكم أبو عمر: إطار العمل ليس شيئًا تبنيه مرة واحدة وتنساه. هو كائن حي ينمو ويتطور مع تطبيقك. كن مستعدًا دائمًا لتحسينه وتطويره. ابدأ صغيرًا، ولكن فكر بشكل كبير. حتى لو بدأت بتطبيق بسيط لـ POM، فأنت تضع الأساس الصحيح لنظام قوي ومستدام في المستقبل. المهم تبدأ صح. بالتوفيق يا أبطال! 🚀

أبو عمر

سجل دخولك لعمل نقاش تفاعلي

كافة المحادثات خاصة ولا يتم عرضها على الموقع نهائياً

آراء من النقاشات

لا توجد آراء منشورة بعد. كن أول من يشارك رأيه!

آخر المدونات

أتمتة العمليات

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

كف عن تشتيت نفسك كل صباح بين Jira وGitHub والإيميلات. تعلم معي، أبو عمر، كيف تبني ورك فلو أتمتة يرسل لك ملخصاً ذكياً ومنسقاً بإنجازات...

12 فبراير، 2026 قراءة المزيد
البودكاست