كيفية تشغيل حالات اختبار متعددة في TestNG التالي

⚡ ملخص ذكي

تشغيل حالات اختبار متعددة باستخدام TestNG جناح في Selenium يتيح لك هذا الدليل تشغيل عدة فئات أو حزم أو مجموعات فرعية من ملف testng.xml واحد. ويغطي هذا الدليل العملي الخيوط المتوازية، وهيكلية المجموعات، وإعداد التقارير، والمساعدة بالذكاء الاصطناعي للتطبيقات الحديثة. TestNG مشاريع الإصدار 7.x.

  • 🧵 الخيوط المتوازية: قم بتعيين thread-count و parallel="tests" لتقليل وقت التشغيل الإجمالي عبر المتصفحات والحزم.
  • 🗂️ التسلسل الهرمي للأجنحة: يمكن لملف testng.xml الرئيسي أن يسرد إدخالات ملفات المجموعات الفرعية لربط مجموعات متعددة في مشغل واحد.
  • ⚙️ TestNG جاهز 7.x: تتوافق الأمثلة مع TestNG و7.10 Selenium أربعة برامج تشغيل تابعة لـ W3C، تحل محل البرامج القديمة Firefoxتوصيلات أسلاك السائق.
  • 📊 التقارير الذكية: تساعد مستويات الإسهاب من 1 إلى 10 وتقارير HTML القابلة للإرسال عبر البريد الإلكتروني في تشخيص فشل الخيوط المتوازية بسرعة.
  • 🤖 التنسيق باستخدام الذكاء الاصطناعي: تقوم أدوات الجدولة المدعومة بالذكاء الاصطناعي بإعادة ترتيب مجموعات المهام وإعادة محاولتها وتقسيمها بناءً على بيانات التقلبات والمدة التاريخية.

تشغيل حالات اختبار متعددة باستخدام TestNG جناح في Selenium

TestNG تتيح لك هذه الميزة تشغيل أساليب الاختبار، والفئات، ومجموعات الاختبارات الكاملة بالتوازي داخل مشروع واحد. يقلل التنفيذ المتوازي من إجمالي وقت التشغيل لأن الخيوط تبدأ الاختبارات بشكل متزامن بدلاً من تشغيلها واحدة تلو الأخرى. يشرح هذا الدليل كيفية تشغيل فئات متعددة (مجموعات اختبارات مختلفة) باستخدام هذه الميزة. TestNG 7.x مع Selenium برنامج تشغيل الويب.

الخطوة 1) إنشاء أ TestNGملف XML لتنفيذ الاختبارات

لإنشاء التكوين، اتبع الخطوات التالية.

  1. أنشئ مشروعًا جديدًا في Eclipse.
  2. أنشئ حزمتين في المشروع (سمِّهما). com.suite1 و com.suite2).
  3. أنشئ فئة في كل حزمة (سمّها). Flipkart.java و Snapdeal.java) وانسخ الكود أدناه إلى الفئات المعنية.
  4. أنشئ ملفًا جديدًا في مشروعك وقم بتسميته اختبار.xml. تأكد من أن TestNG تم تثبيت الملحق (التعليمات متوفرة) اضغط هنايحتوي ملف testng.xml على جميع الإعدادات مثل أسماء الفئات وأسماء الاختبارات وأسماء المجموعات.

Flipkart.java

package com.suite1;

import java.util.concurrent.TimeUnit;

import org.openqa.selenium.Alert;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.interactions.Actions;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;

public class Flipkart {

    WebDriver driver = new FirefoxDriver();
    String username = ""; // Change to your username and password
    String password = "";

    // This method navigates to the Flipkart URL
    @BeforeClass
    public void init() {
        driver.manage().window().maximize();
        driver.manage().timeouts().implicitlyWait(60, TimeUnit.SECONDS);
        driver.navigate().to("https://www.flipkart.com");
    }

    // Log in to Flipkart
    @Test
    public void login() {
        driver.findElement(By.partialLinkText("Login")).click();
        driver.findElement(By.cssSelector(".fk-input.login-form-input.user-email")).sendKeys(username);
        driver.findElement(By.cssSelector(".fk-input.login-form-input.user-pwd")).sendKeys(password);
        driver.findElement(By.cssSelector(".submit-btn.login-btn.btn")).click();
    }

    // Search for a product
    @Test
    public void searchAndSelectProduct() {
        driver.findElement(By.id("fk-top-search-box")).sendKeys("moto g3");
        driver.findElement(By.cssSelector("search-bar-submit.fk-font-13.fk-font-bold")).click();
        String css = ".gd-row.browse-grid-row:nth-of-type(1) > div:nth-child(1)>div>div:nth-child(2)>div>a";
        driver.findElement(By.cssSelector(css)).click();
    }

    @Test
    public void buyAndRemoveFromCart() {
        driver.findElement(By.cssSelector(".btn-express-checkout.btn-big.current")).click();
        driver.findElement(By.cssSelector(".remove.fk-inline-block")).click();
        Alert a = driver.switchTo().alert();
        a.accept();
    }

    @Test
    public void logout() {
        Actions s = new Actions(driver);
        WebElement user = driver.findElement(By.partialLinkText(username));
        s.moveToElement(user).build().perform();
        driver.findElement(By.linkText("Logout")).click();
    }

    @AfterClass
    public void quit() {
        driver.close();
    }
}

SnapDeal.java

package com.suite2;

import java.util.concurrent.TimeUnit;

import org.openqa.selenium.Alert;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.interactions.Actions;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;

public class SnapDeal {

    WebDriver driver = new FirefoxDriver();
    String username = ""; // Change to your username and password
    String password = "";
    String pinCode = "";

    // This method navigates to the Snapdeal URL
    @BeforeClass
    public void init() {
        driver.manage().window().maximize();
        driver.manage().timeouts().implicitlyWait(60, TimeUnit.SECONDS);
        driver.navigate().to("https://www.snapdeal.com");
    }

    @Test
    public void login() {
        driver.findElement(By.xpath("//button[text()='Login']")).click();
        driver.switchTo().frame("loginIframe");
        driver.findElement(By.cssSelector("div[onClick='getLoginForm()']")).click();
        driver.findElement(By.id("j_username")).sendKeys(username);
        driver.findElement(By.id("j_password_login")).sendKeys(password);
        driver.findElement(By.id("signin_submit")).click();
        driver.switchTo().defaultContent();
    }

    @Test
    public void searchAndSelectProduct() {
        driver.findElement(By.cssSelector(".col-xs-20.searchformInput.keyword")).sendKeys("iphone 6s");
        driver.findElement(By.cssSelector(".sd-icon.sd-icon-search")).click();
        String css = ".product_grid_row:nth-of-type(1)>div:nth-child(1)";
        driver.findElement(By.cssSelector(css)).click();
    }

    @Test
    public void buyAndRemoveFromCart() {
        driver.findElement(By.xpath("//li[contains(text(),'Silver')]")).click();
        driver.findElement(By.id("pincode-check")).sendKeys(pinCode);
        driver.findElement(By.id("buy-button-id")).click();
        driver.findElement(By.cssSelector("i[title='Delete Item']")).click();
        Alert a = driver.switchTo().alert();
        a.accept();
    }

    @Test
    public void logout() {
        driver.findElement(By.linkText("START SHOPPING NOW")).click();
        Actions s = new Actions(driver);
        WebElement user = driver.findElement(By.cssSelector(".sd-icon.sd-icon-user"));
        s.moveToElement(user).build().perform();
        driver.findElement(By.linkText("Logout")).click();
    }

    @AfterClass
    public void quit() {
        driver.close();
    }
}

TestNG. أكس

<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">

<suite thread-count="2" verbose="1" name="Gmail Suite" parallel="tests">

  <test name="flipkart">
    <classes>
      <class name="com.suite1.Flipkart"/>
    </classes>
  </test>

  <test name="Myntra">
    <classes>
      <class name="com.suite2.SnapDeal"/>
    </classes>
  </test>
</suite>

يبدو هيكل المشروع النهائي كما في المثال أدناه.

خلق TestNGملف .xml لتنفيذ الاختبار

الخطوة 2) التنفيذ الموازي في TestNG

بعد حفظ ملف XML المذكور أعلاه، تتمثل الخطوة التالية في تشغيل الاختبارات المتوازية. يظهر الكود أدناه.

التنفيذ الموازي في TestNG

1) عدد الخيوط: يحدد عدد الخيوط TestNG يمكن تشغيلها للتنفيذ المتوازي. القيمة الأعلى تُشغّل المزيد من الاختبارات في وقت واحد، حتى الحد الأقصى لوحدة المعالجة المركزية.

2) مطوليسجل تفاصيل التنفيذ في وحدة التحكم. تتراوح القيم المسموح بها من 1 إلى 10. القيم الأعلى تنتج سجلات أكثر تفصيلاً ودقة.

3) الاسماسم الجناح. إليك هو:Gmail جناح".

4) متوازي: يخبر TestNG ما الذي سيتم تشغيله بالتزامن؟ القيم الصالحة هي الاختبارات، والفئات، والأساليب، أو النسخ. القيمة الافتراضية هي لا شيء.

انقر بزر الماوس الأيمن على ملف testng.xml وحدد تشغيل كـ > TestNG التاليبمجرد الانتهاء، سترى النتائج المجمعة.

عند تنفيذ الكود أعلاه، سوف تحصل على الإخراج التالي.

الإخراج:

التنفيذ الموازي في TestNG

1) اسم المجموعة المحددة في ملف testng.xml.

التنفيذ الموازي في TestNG

2) اسم الاختبار المحدد في ملف testng.xml.

التنفيذ الموازي في TestNG

3) اسم الفئة المعلنة في ملف testng.xml.

التنفيذ الموازي في TestNG

4) أسماء الطرق التي تم وضع علامة @Test عليها في ملف .java.

التنفيذ الموازي في TestNG

يتم تشغيل نفس التدفق لاختبار SnapDeal، لذلك يتم تنفيذ كلا الفئتين جنبًا إلى جنب.

الخطوة 3) تشغيل مجموعات اختبار متعددة من ملف testng.xml رئيسي واحد

من المتطلبات الشائعة في المشاريع الكبيرة ربط عدة ملفات testng.xml في مشغل واحد. TestNG يدعم الإصدار 7.x مجموعة رئيسية تشير إلى مجموعة فرعية ملف المجموعة يتم حفظ كل مجموعة فرعية على حدة، بحيث يمكن لكل مجموعة فرعية الاحتفاظ بعدد مؤشرات الترابط والمستمعين والمعلمات الخاصة بها. ثم يتم توجيه المجموعة الأصلية إلى مسارها. ويتم تشغيل الملف الأصلي فقط من Eclipse، Maven، أو سطر الأوامر.

<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="Parent Suite" parallel="tests" thread-count="4">
  <suite-files>
    <suite-file path="./flipkart-suite.xml"/>
    <suite-file path="./snapdeal-suite.xml"/>
  </suite-files>
</suite>

يحافظ هذا النمط على فصل مجموعات اختبارات الانحدار، والاختبارات الأولية، واختبارات السلامة، مع إمكانية إعادة استخدامها. يمكنك أيضًا تشغيل الملف الرئيسي من Maven Surefire عن طريق التعيين <suiteXmlFile>parent-suite.xml</suiteXmlFile> داخل إعدادات المكون الإضافي، مما يجعل نفس التخطيط المتوازي يعمل في خطوط أنابيب التكامل المستمر.

الخطوة 4) أفضل الممارسات للتوازي TestNG يدير

  • دبوس TestNG 7.X: استعمل TestNG 7.10 أو أحدث مع Selenium 4- لذلك تتصرف برامج التشغيل المتوافقة مع معايير W3C بشكل متسق عبر الخيوط.
  • تجنب الحالة المشتركة: نقل ويب درايفر قم بتحويل الحقل إلى ThreadLocal بحيث يحتفظ كل خيط بجلسة خاصة به.
  • اضبط عدد الخيوط: ابدأ بعدد أنوية وحدة المعالجة المركزية، ثم راقب تقرير HTML القابل للإرسال عبر البريد الإلكتروني وتحميل الشبكة قبل رفعه.
  • عزل بيانات الاختبار: استخدم مستخدمين وسلال تسوق ورموز PIN فريدة لكل عملية تسجيل دخول حتى لا تتعارض عمليات تسجيل الدخول.
  • التقاط لقطات شاشة عند حدوث خطأ: قم بتوصيلها من خلال ITestListener لتصحيح أخطاء التشغيل المتوازي غير المستقر بشكل أسرع.
  • استخدم المساعدة بالذكاء الاصطناعي: أدوات مثل Testimيمكن لـ mabl و CodiumAI الإشارة إلى الاختبارات غير المستقرة واقتراح محددات مستقرة قبل التشغيل التالي.

خاتمة

يوضح المثال أعلاه كيفية الاستخدام TestNG لتنفيذ اختبارات متوازية. TestNG يُتيح لك الإصدار 7.x ملف XML واحدًا لتشغيل فئات اختبار متعددة، وربط عدة مجموعات فرعية، وضبط الخيوط المتوازية، وهو أمر بالغ الأهمية. Selenium تُنجز المشاريع بشكل أسرع بكثير.

الأسئلة الشائعة

ضع كل فصل في مكانه الخاص قم بوضع الوسم داخل ملف testng.xml، ثم قم بتعيين parallel="tests" وعدد الخيوط إلى 2 على الأقل. TestNG يبدأ كلا الاختبارين على خيوط منفصلة، ​​لذلك يتم تنفيذ الفئات بشكل متزامن بدلاً من التسلسل.

نعم. أنشئ مجموعة ملفات رئيسية تسرد الملفات الفرعية بداخلها كل مسار لملفات المجموعة الفرعية يُشغّل إعداداته الخاصة. يعمل هذا النمط في Eclipse، مافن شورفاير، و Gradleويحظى بدعم من TestNG من الإصدار 6 فصاعدًا، بما في ذلك الإصدار الحالي 7.x.

تقبل السمة المتوازية الاختبارات، والفئات، والأساليب، والمثيلات، أو لا شيء. اختر الاختبارات عندما يكون كل الوسم مكتفٍ ذاتيًا، والفئات لعزل الفئة بأكملها، والأساليب عندما تكون أساليب @Test الفردية آمنة للاستخدام في بيئة متعددة الخيوط. القيمة الافتراضية هي لا شيء، مما يؤدي إلى تشغيل كل شيء بالتسلسل.

استخدم ThreadLocal أو قم بتهيئة برنامج التشغيل داخل كتلة @BeforeMethod بدلاً من حقل ثابت. عندها، يمتلك كل خيط جلسة متصفح خاصة به، مما يزيل حالات التزامن التي تؤدي إلى تعطل العمليات المتوازية. TestNG يعمل على Selenium الشبكة.

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

نعم. تقوم أدوات الجدولة المدعومة بالذكاء الاصطناعي في Launchable وBuildPulse بقياس المدة التاريخية ومعدل التأخير لكل اختبار، ثم تقسم ملف testng.xml إلى أجزاء متوازنة. يعمل كل جزء على وكيل منفصل، مما يؤدي إلى انخفاض إجمالي وقت التشغيل الفعلي مع الحفاظ على مستوى عالٍ من الاستخدام المتوازي.

تلخيص هذه التدوينة بـ: