موفر البيانات في TestNG: Selenium مثال على تحديد المعلمات

⚡ ملخص ذكي

البارامترات في Selenium يقوم بتشغيل طريقة اختبار واحدة بشكل متكرر على مجموعات بيانات مختلفة، مما يحول نصًا برمجيًا واحدًا إلى تغطية تعتمد على البيانات. TestNG يوفر آليتين لذلك: التعليق التوضيحي @Parameters المدعوم بواسطة testng.xml، والتعليق التوضيحي @DataProvider الذي يُرجع مصفوفة كائنات ثنائية الأبعاد.

  • 🎯 الغرض الأساسي: تعمل المعلمات على إزالة القيم المضمنة في نصوص الاختبار بحيث يتم التحقق من صحة كل مجموعة إدخال يجب أن يدعمها التطبيق بنفس المنطق.
  • 📄 آلية XML: تقوم التعليقات التوضيحية @Parameters بقراءة أزواج الاسم والقيمة المعلنة في testng.xml، وهو ما يناسب المدخلات على نمط التكوين حيث يظل عدد التركيبات صغيرًا.
  • 🏷️ أولوية النطاق: تتجاوز المعلمات المعلنة على مستوى الاختبار المعلمات التي تحمل نفس الاسم على مستوى المجموعة، بينما تستمر الفئات خارج هذا الاختبار في قراءة قيمة المجموعة.
  • 🗂️ آلية موفر البيانات: تقوم الدالة التي تحمل التعليق التوضيحي @DataProvider بإرجاع Object[][]، و TestNG يستدعي الاختبار مرة واحدة لكل صف، مع تمرير كل عمود كوسيط.
  • 🔗 مقدمو الخدمات الخارجيون: إن وضع علامة على الموفر كـ static وتعيين dataProviderClass على @Test يسمح لعدة فئات اختبار بمشاركة مصدر بيانات واحد.
  • 🧭 مجموعات البيانات الديناميكية: يؤدي قبول Method أو ITestContext كوسيط موفر إلى إرجاع بيانات مختلفة لكل طريقة اختبار أو لكل مجموعة مضمنة.
  • 🛡️ الإخفاقات الشائعة: تتسبب حالات عدم تطابق الأنواع بين قيم XML ومعاملات الأساليب، والمعلمات المفقودة التي يتم حلها باستخدام @Optional، في معظم أخطاء التعليقات التوضيحية.

موفر البيانات في TestNG

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

البارامترات في Selenium

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

نوع المعلمة في TestNG

لتوضيح عملية تحديد المعلمات بشكل أفضل، سنستعرض خيارات تحديد المعلمات في أحد أكثر الأطر شيوعًا لـ Selenium WebDriver — TestNG.

هناك طريقتان والتي من خلالها يمكننا تحقيق المعلمة في TestNG:

  1. مع مساعدة من شرح المعلمات و مبادئ السلوك TestNG XML ملف.

نوع المعلمة في TestNG

  1. مع مساعدة من DataProvider حاشية. ملاحظة.

نوع المعلمة في TestNG

نوع المعلمة في TestNG

يلخص الرسم البياني أعلاه التقسيم: يمكن تعريف المعلمات من ملف testng.xml على مستوى المجموعة أو الاختبار، بينما يمكن للمعلمة من موفر البيانات أن تقبل Method و ITestContext كحجة مستقلة. فلندرسها بالتفصيل.

شرح المعلمات في TestNG

شرح المعلمات في TestNG هي طريقة تُستخدم لتمرير القيم إلى دوال الاختبار كوسائط باستخدام ملف XML. قد يُطلب من المستخدمين تمرير هذه القيم إلى دوال الاختبار أثناء التشغيل. يمكن استخدام طريقة التعليق التوضيحي @Parameters في أي دالة تحتوي على التعليقات التوضيحية @Test أو @Before أو @After أو @Factory.

شرح المعلمات باستخدام Testng.xml

اختر استخدام المعلمات باستخدام التعليقات التوضيحية عندما لا ترغب في التعامل مع التعقيد ويكون عدد مجموعات الإدخال صغيرًا.

دعونا نرى كيف يعمل هذا.

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

الخطوة 1) قم بتشغيل المتصفح وانتقل إلى Google.com

الخطوة 2) أدخل كلمة البحث

شرح المعلمات باستخدام Testng.Xml

الخطوة 3) تحقق من أن القيمة المدخلة هي نفسها القيمة التي توفرها بيانات الاختبار الخاصة بنا

الخطوة 4) كرر الخطوتين 2 و3 حتى يتم إدخال جميع القيم

مؤلف الاختبار مفتاح البحث
Guru99 الهند
Krishna الولايات المتحدة الأمريكية
بهوبيش الصين

إليك مثال على كيفية القيام بذلك بدون المعلمات:

package parameters;

import org.testng.annotations.Test;
import org.testng.AssertJUnit;
import java.time.Duration;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;

public class NoParameterWithTestNGXML {
    WebDriver driver;

    @Test
    public void testNoParameter() throws InterruptedException {
        String author = "guru99";
        String searchKey = "india";

        driver = new FirefoxDriver();
        driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));

        driver.get("https://google.com");
        WebElement searchText = driver.findElement(By.name("q"));
        // Searching text in the Google text box
        searchText.sendKeys(searchKey);

        System.out.println("Welcome ->" + author + " Your search key is->" + searchKey);
        Thread.sleep(3000);
        System.out.println("Value in Google Search Box = " + searchText.getDomProperty("value")
                + " ::: Value given by input = " + searchKey);
        // Verifying the value in the Google search box
        AssertJUnit.assertTrue(searchText.getDomProperty("value").equalsIgnoreCase(searchKey));
    }
}

⚠️ Selenium ملاحظة 4: ثلاثة أسطر في النسخة الأصلية من هذا المثال لم تعد تُترجم أو أصبحت مهملة في الإصدار الحالي Selenium إطلاق. System.setProperty("webdriver.gecko.driver", …) غير ضروري من Selenium 4.6 وما بعدها لأن Selenium يقوم المدير بحل ملف تعريف برنامج التشغيل تلقائيًا. implicitlyWait(10, TimeUnit.SECONDS) تمت إزالة الحمل الزائد في Selenium 4 واستُبدل بـ implicitlyWait(Duration.ofSeconds(10)). getAttribute() تم إيقافها في Selenium 4.27، لذا فإن قراءة مربع نص تستخدم getDomProperty("value"). كل مثال أدناه يطبق نفس التصحيحات الثلاثة.

ادرس المثال أعلاه وتخيل مدى تعقيد الكود عندما يتم تكرار ذلك لثلاث مجموعات إدخال.

والآن دعونا نحدد معلمات ذلك باستخدام TestNGللقيام بذلك، عليك القيام بما يلي:

  • قم بإنشاء ملف XML الذي سيقوم بتخزين المعلمات
  • أضف التعليق التوضيحي @Parameters في الاختبار

شرح المعلمات باستخدام Testng.Xml

إليكم الكود الكامل.

مستوى الاختبار TestNG. أكس

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name="TestSuite" thread-count="3">
  <parameter name="author" value="Guru99" />
  <parameter name="searchKey" value="India" />
  <test name="testGuru">
    <parameter name="searchKey" value="UK" />
    <classes>
      <class name="parameters.ParameterWithTestNGXML"></class>
    </classes>
  </test>
</suite>

المعلمة معTestNGملف XML.java

package parameters;

import org.testng.AssertJUnit;
import java.time.Duration;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;

import org.testng.annotations.Optional;
import org.testng.annotations.Parameters;
import org.testng.annotations.Test;

public class ParameterWithTestNGXML {
    WebDriver driver;

    @Test
    @Parameters({"author", "searchKey"})
    public void testParameterWithXML(@Optional("Abc") String author, String searchKey)
            throws InterruptedException {

        driver = new FirefoxDriver();
        driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
        driver.get("https://google.com");

        WebElement searchText = driver.findElement(By.name("q"));
        // Searching text in the Google text box
        searchText.sendKeys(searchKey);

        System.out.println("Welcome ->" + author + " Your search key is->" + searchKey);
        Thread.sleep(3000);
        System.out.println("Value in Google Search Box = " + searchText.getDomProperty("value")
                + " ::: Value given by input = " + searchKey);
        // Verifying the value in the Google search box
        AssertJUnit.assertTrue(searchText.getDomProperty("value").equalsIgnoreCase(searchKey));
    }
}

لتشغيل البرنامج النصي، حدد ملف XML وقم بتشغيله كـ TestNG جناح.

انقر بزر الماوس الأيمن على ملف .xml -> تشغيل كـ -> TestNG جناح (ملاحظة: جناح)

المعلمة معTestNGملف XML.java

يمكن تحديد المعلمات على مستويين:

  1. مستويات الأجنحة — المعايير داخل <suite> علامة TestNG ملف XML عبارة عن معلمات على مستوى المجموعة.
  2. مستوى الاختبار — المعايير داخل <test> علامة TestNG ملف XML عبارة عن معلمات على مستوى الاختبار.

إليكم نفس الاختبار مع معلمات على مستوى المجموعة:

المعلمة معTestNGملف XML.java

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

المعلمة معTestNGملف XML.java

فحص الجهاز

العدد رقم 1: يؤدي وجود قيمة معلمة في ملف testng.xml لا يمكن تحويل نوعها إلى معلمة طريقة الاختبار المقابلة إلى ظهور خطأ.

خذ بعين الاعتبار المثال التالي:

استكشاف الأخطاء وإصلاحها

هنا، تساوي سمة "المؤلف" 'Guru99'، وهو عبارة عن سلسلة نصية، بينما تتوقع طريقة الاختبار المقابلة قيمة عددية صحيحة، لذلك يتم طرح استثناء.

العدد رقم 2: لا توجد قيمة مقابلة لـ @Parameters في ملف testng.xml.

يمكنك حل هذه المشكلة عن طريق إضافة @Optional تعليق توضيحي إلى المعلمة المقابلة في طريقة الاختبار.

استكشاف الأخطاء وإصلاحها

العدد رقم 3: تريد اختبار قيم متعددة لنفس المعلمة باستخدام ملف testng.xml.

باختصار، هذا غير ممكن. يمكنك استخدام عدة معلمات مختلفة، لكن كل معلمة لا تقبل إلا قيمة واحدة. هذا يمنع تضمين القيم مباشرةً في البرنامج النصي، ويحافظ على إمكانية إعادة استخدام الكود - اعتبره ملف تهيئة للبرنامج النصي. إذا كنت بحاجة إلى قيم متعددة لمعلمة واحدة، فاستخدم موفر بيانات (DataProvider) بدلاً من ذلك.

مزود البيانات في TestNG

مزود البيانات في TestNG هي طريقة تُستخدم عندما يحتاج المستخدم إلى تمرير معلمات معقدة. يجب إنشاء المعلمات المعقدة من Java يمكن تمرير الكائنات المعقدة، أو الكائنات من ملفات الخصائص، أو الكائنات من قاعدة البيانات، عبر دالة موفر البيانات. هذه الدالة مُعَلَّمة بالتعليق التوضيحي @DataProvider، وتُعيد مصفوفة من الكائنات.

المعلمات باستخدام Dataprovider

يُعدّ استخدام التعليق التوضيحي @Parameters سهلاً، ولكن لاختبار مجموعات بيانات متعددة، نحتاج إلى استخدام موفر بيانات.

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

يتم تحقيق هذا المفهوم القائم على البيانات من خلال @DataProvider تعليق توضيحي في TestNG.

المعلمات باستخدام Dataprovider

لديها واحد فقط السمة، 'الاسم'إذا لم تحدد سمة الاسم، فسيكون اسم موفر البيانات هو نفسه اسم الطريقة المقابلة.

يقوم مزود البيانات بإرجاع ثنائي الأبعاد Java موضوع يتم استدعاء دالة الاختبار M مرة لمصفوفة كائنات بحجم M×N. على سبيل المثال، إذا أعاد موفر البيانات مصفوفة من كائنات بحجم 2×3، فسيتم استدعاء حالة الاختبار المقابلة مرتين مع 3 معلمات في كل مرة.

المعلمات باستخدام Dataprovider

مثال كامل

المعلمات باستخدام Dataprovider

package parameters;

import java.time.Duration;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;

import org.testng.Assert;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

public class ParameterByDataprovider {
    WebDriver driver;

    @BeforeTest
    public void setup() {
        // Create the Firefox driver object
        driver = new FirefoxDriver();
        driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
        driver.get("https://google.com");
    }

    /** Test case to verify the Google search box */
    @Test(dataProvider = "SearchProvider")
    public void testMethod(String author, String searchKey) throws InterruptedException {
        WebElement searchText = driver.findElement(By.name("q"));
        // Search value in the Google search box
        searchText.sendKeys(searchKey);
        System.out.println("Welcome ->" + author + " Your search key is->" + searchKey);
        Thread.sleep(3000);
        String testValue = searchText.getDomProperty("value");
        System.out.println(testValue + "::::" + searchKey);
        searchText.clear();
        // Verify if the value in the Google search box is correct
        Assert.assertTrue(testValue.equalsIgnoreCase(searchKey));
    }

    /**
     * @return Object[][] where the first column contains 'author'
     * and the second column contains 'searchKey'
     */
    @DataProvider(name = "SearchProvider")
    public Object[][] getDataFromDataprovider() {
        return new Object[][] {
            { "Guru99", "India" },
            { "Krishna", "UK" },
            { "Bhupesh", "USA" }
        };
    }
}

استدعاء DataProvider من فئة مختلفة

بشكل افتراضي، يوجد موفر البيانات في نفس فئة طريقة الاختبار، أو في فئتها الأساسية. لوضعه في فئة أخرى، اجعل طريقة موفر البيانات ساكن وأضف السمة dataProviderClass إلى @اختبار حاشية. ملاحظة.

استدعاء DataProvider من فئة مختلفة

Code مثال

استدعاء DataProvider من فئة مختلفة

معلمة TestClassDataproviderWithClassLevel.java

package parameters;

import java.time.Duration;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.testng.Assert;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;

public class ParameterDataproviderWithClassLevel {
    WebDriver driver;

    @BeforeTest
    public void setup() {
        driver = new FirefoxDriver();
        driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
        driver.get("https://google.com");
    }

    @Test(dataProvider = "SearchProvider", dataProviderClass = DataproviderClass.class)
    public void testMethod(String author, String searchKey) throws InterruptedException {
        WebElement searchText = driver.findElement(By.name("q"));
        // Search text in the Google text box
        searchText.sendKeys(searchKey);
        System.out.println("Welcome ->" + author + " Your search key is->" + searchKey);
        Thread.sleep(3000);
        // Get text from the search box
        String testValue = searchText.getDomProperty("value");
        System.out.println(testValue + "::::" + searchKey);
        searchText.clear();
        // Verify if the search box has the correct value
        Assert.assertTrue(testValue.equalsIgnoreCase(searchKey));
    }
}

DataproviderClass.java

package parameters;

import org.testng.annotations.DataProvider;

public class DataproviderClass {

    @DataProvider(name = "SearchProvider")
    public static Object[][] getDataFromDataprovider() {
        return new Object[][] {
            { "Guru99", "India" },
            { "Krishna", "UK" },
            { "Bhupesh", "USA" }
        };
    }
}

أنواع المعلمات في Dataprovider

يدعم أسلوب DataProvider نوعين من المعلمات.

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

أنواع المعلمات في Dataprovider

في المثال التالي:

  • نتحقق مما إذا كان اسم الطريقة هو testMethodA
  • إذا كانت الإجابة بنعم، فأرجع مجموعة واحدة من القيم
  • وإلا، فأرجع مجموعة أخرى من القيم
package parameters;

import java.lang.reflect.Method;
import java.time.Duration;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.testng.Assert;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

public class ParameterByMethodInDataprovider {

    WebDriver driver;

    @BeforeTest
    public void setup() {
        driver = new FirefoxDriver();
        driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
        driver.get("https://google.com");
    }

    @Test(dataProvider = "SearchProvider")
    public void testMethodA(String author, String searchKey) throws InterruptedException {
        WebElement searchText = driver.findElement(By.name("q"));
        searchText.sendKeys(searchKey);
        // Print author and search string
        System.out.println("Welcome ->" + author + " Your search key is->" + searchKey);
        Thread.sleep(3000);
        String testValue = searchText.getDomProperty("value");
        System.out.println(testValue + "::::" + searchKey);
        searchText.clear();
        Assert.assertTrue(testValue.equalsIgnoreCase(searchKey));
    }

    @Test(dataProvider = "SearchProvider")
    public void testMethodB(String searchKey) throws InterruptedException {
        WebElement searchText = driver.findElement(By.name("q"));
        searchText.sendKeys(searchKey);
        // Print only the search string
        System.out.println("Welcome ->Unknown user Your search key is->" + searchKey);
        Thread.sleep(3000);
        String testValue = searchText.getDomProperty("value");
        System.out.println(testValue + "::::" + searchKey);
        searchText.clear();
        Assert.assertTrue(testValue.equalsIgnoreCase(searchKey));
    }

    /** The DataProvider returns values based on the test method name */
    @DataProvider(name = "SearchProvider")
    public Object[][] getDataFromDataprovider(Method m) {
        if (m.getName().equalsIgnoreCase("testMethodA")) {
            return new Object[][] {
                { "Guru99", "India" },
                { "Krishna", "UK" },
                { "Bhupesh", "USA" }
            };
        } else {
            return new Object[][] {
                { "Canada" },
                { "Russia" },
                { "Japan" }
            };
        }
    }
}

هنا هو الإخراج:

أنواع المعلمات في Dataprovider

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

في الحياة الواقعية، يمكنك استخدام ITestContext لتغيير قيم المعلمات بناءً على أساليب الاختبار أو المضيفين أو تكوينات الاختبار.

أنواع المعلمات في Dataprovider

في مثال الكود التالي:

  • لدينا مجموعتان، أ و ب
  • يتم تعيين كل طريقة اختبار لمجموعة
  • إذا كانت قيمة المجموعة هي A، فسيتم إرجاع مجموعة بيانات واحدة
  • إذا كانت قيمة المجموعة هي B، فسيتم إرجاع مجموعة بيانات أخرى
package parameters;

import java.time.Duration;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.testng.Assert;
import org.testng.ITestContext;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

public class ParameterByITestContextInDataprovider {
    WebDriver driver;

    @BeforeTest(groups = {"A", "B"})
    public void setup() {
        driver = new FirefoxDriver();
        driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
        driver.get("https://google.com");
    }

    @Test(dataProvider = "SearchProvider", groups = "A")
    public void testMethodA(String author, String searchKey) throws InterruptedException {
        WebElement searchText = driver.findElement(By.name("q"));
        searchText.sendKeys(searchKey);
        System.out.println("Welcome ->" + author + " Your search key is->" + searchKey);
        Thread.sleep(3000);
        String testValue = searchText.getDomProperty("value");
        System.out.println(testValue + "::::" + searchKey);
        searchText.clear();
        Assert.assertTrue(testValue.equalsIgnoreCase(searchKey));
    }

    @Test(dataProvider = "SearchProvider", groups = "B")
    public void testMethodB(String searchKey) throws InterruptedException {
        WebElement searchText = driver.findElement(By.name("q"));
        searchText.sendKeys(searchKey);
        System.out.println("Welcome ->Unknown user Your search key is->" + searchKey);
        Thread.sleep(3000);
        String testValue = searchText.getDomProperty("value");
        System.out.println(testValue + "::::" + searchKey);
        searchText.clear();
        Assert.assertTrue(testValue.equalsIgnoreCase(searchKey));
    }

    /** The DataProvider supplies an Object array based on ITestContext */
    @DataProvider(name = "SearchProvider")
    public Object[][] getDataFromDataprovider(ITestContext c) {
        Object[][] groupArray = null;
        for (String group : c.getIncludedGroups()) {
            if (group.equalsIgnoreCase("A")) {
                groupArray = new Object[][] {
                    { "Guru99", "India" },
                    { "Krishna", "UK" },
                    { "Bhupesh", "USA" }
                };
                break;
            } else if (group.equalsIgnoreCase("B")) {
                groupArray = new Object[][] {
                    { "Canada" },
                    { "Russia" },
                    { "Japan" }
                };
                break;
            }
        }
        return groupArray;
    }
}

ملاحظة: إذا قمت بتشغيل TestNG عند استدعاء الفئة مباشرةً، يتم استدعاء موفر البيانات أولاً، ولا يستطيع الموفر قراءة معلومات المجموعات لأنها غير متاحة بعد. أما عند استدعاء الفئة عبر ملف testng.xml، فتصبح معلومات المجموعات متاحة من خلال ITestContext. استخدم ملف XML التالي لتشغيل الاختبار:

<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name="test-parameter">

  <test name="example1">
    <groups>
      <run>
        <include name="A" />
      </run>
    </groups>
    <classes>
      <class name="parameters.ParameterByITestContextInDataprovider" />
    </classes>
  </test>

  <test name="example2">
    <groups>
      <run>
        <include name="B" />
      </run>
    </groups>
    <classes>
      <class name="parameters.ParameterByITestContextInDataprovider" />
    </classes>
  </test>

</suite>

تم تغطية كلا الآليتين الآن، لذا فإن السؤال العملي هو أي منهما يجب اللجوء إليه.

@Parameters مقابل @DataProvider: أيهما الأفضل استخداماً؟

لا يمكن استبدال النهجين ببعضهما البعض. يعتمد القرار على عدد تركيبات القيم التي يحتاجها الاختبار ومصدر تلك القيم.

معيار @Parameters + testng.xml @DataProvider
القيم لكل معلمة واحد فقط صفوف غير محدودة
مصدر البيانات نص ثابت في ملف XML Java كود، إكسل، CSV، قاعدة بيانات، واجهة برمجة التطبيقات (API)
الأنواع المدعومة تحويل القيم من نوع String اي Java موضوع
استدعاءات الاختبار مرة واحدة لكل تكوين مرة واحدة لكل صف بيانات
يتطلب تغيير البيانات تحرير ملف XML تعديل المصدر، غالباً لا يتطلب إعادة تجميع
أفضل مناسب لـ قيم البيئة والتكوين مثل المتصفح، URL، أوراق اعتماد اختبار قائم على البيانات عبر العديد من مجموعات المدخلات

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

كيفية قراءة بيانات الاختبار من ملف إكسل باستخدام موفر البيانات

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

  1. أضف التبعية. تضمن org.apache.poi:poi-ooxml في مافن الخاص بك أو Gradle بناء. الـ ooxml يتعامل البرنامج مع تنسيق .xlsx؛ عادي poi يقرأ فقط ملفات .xls القديمة.
  2. أنشئ المصنف. ضع صف العناوين في الصف 0 وحالة اختبار واحدة لكل صف أسفله، مع عمود واحد لكل وسيطة من وسائط طريقة الاختبار.
  3. اقرأ الورقة في مصفوفة. قم بتحديد حجم Object[][] بناءً على عدد الصفوف والخلايا بحيث يتم التقاط الصفوف الجديدة دون تغييرات في التعليمات البرمجية.
  4. أعده إلى المورد. يبقى توقيع طريقة الاختبار كما هو تمامًا كما كان من قبل.
import java.io.FileInputStream;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.testng.annotations.DataProvider;

public class ExcelDataProvider {

    @DataProvider(name = "SearchProvider")
    public Object[][] readSearchData() throws Exception {
        FileInputStream file = new FileInputStream("src/test/resources/testdata.xlsx");
        Workbook workbook = new XSSFWorkbook(file);
        Sheet sheet = workbook.getSheetAt(0);

        // Skip the header row, so subtract one from the physical row count
        int rows = sheet.getLastRowNum();
        int cols = sheet.getRow(0).getPhysicalNumberOfCells();
        Object[][] data = new Object[rows][cols];

        for (int i = 1; i <= rows; i++) {
            for (int j = 0; j < cols; j++) {
                data[i - 1][j] = sheet.getRow(i).getCell(j).getStringCellValue();
            }
        }
        workbook.close();
        file.close();
        return data;
    }
}

💡 نصيحة: اتصل getStringCellValue() يحدث هذا فقط في الخلايا المنسقة كنص. أما الخلية الرقمية فتُظهر خطأً. IllegalStateExceptionوهذا هو الخطأ الأكثر شيوعًا عندما تحتوي جداول البيانات على معرّفات أو مبالغ. استخدم DataFormatter لقراءة كل نوع خلية كسلسلة نصية، أو تشغيل cell.getCellType() وقم بالتحويل بشكل صريح.

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

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

نعم. الإعداد @DataProvider(name="x", parallel=true) يتم تشغيل الصفوف بشكل متزامن. يحتاج كل خيط إلى مثيل WebDriver خاص به، لذا قم بتخزين برنامج التشغيل في ThreadLocal، وإلا ستتداخل الاختبارات مع بعضها البعض.

نعم. TestNG يقبل Iterator<Object[]>وهي طريقة توفر الصفوف بشكل تدريجي بدلاً من بناء المصفوفة بأكملها في الذاكرة. وهذا يناسب مجموعات البيانات الكبيرة جدًا أو الصفوف المتدفقة من مؤشر قاعدة البيانات.

نعم. AI تقوم الأدوات بإنشاء قيم حدودية، ومدخلات غير صالحة، وسجلات اصطناعية واقعية من مواصفات الحقل. Revراجع المخرجات بحثًا عن التكرارات وتأكد من صحة النتائج المتوقعة قبل إضافة الصفوف إلى الموفر.

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

تُقرأ القيم الموجودة في ملف testng.xml دائمًا كنص. TestNG يحوّلها إلى نوع الوسيط المُعلن، لذا فإن ربط قيمة غير رقمية بوسيط من نوع عدد صحيح سيؤدي إلى فشل العملية. طابق قيمة XML مع توقيع الدالة، أو اقبل سلسلة نصية وقم بتحليلها.

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