موفر البيانات في TestNG: Selenium مثال على تحديد المعلمات
⚡ ملخص ذكي
البارامترات في Selenium يقوم بتشغيل طريقة اختبار واحدة بشكل متكرر على مجموعات بيانات مختلفة، مما يحول نصًا برمجيًا واحدًا إلى تغطية تعتمد على البيانات. TestNG يوفر آليتين لذلك: التعليق التوضيحي @Parameters المدعوم بواسطة testng.xml، والتعليق التوضيحي @DataProvider الذي يُرجع مصفوفة كائنات ثنائية الأبعاد.
عندما نقوم بإنشاء برامج، فإننا نرغب دائمًا في أن تعمل بشكل صحيح مع مجموعات البيانات المختلفة. عندما يتعلق الأمر بـ تجريب لا يكفي فحص مجموعة بيانات واحدة فقط في ذلك البرنامج. نحتاج إلى التأكد من أن النظام يقبل كل تركيبة من البيانات التي يُفترض أن يدعمها. ولتحقيق ذلك، نحتاج إلى تحديد معلمات نصوص الاختبار. وهنا تكمن أهمية تحديد المعلمات.
البارامترات في Selenium
البارامترات في Selenium هي عملية لتحديد معلمات البرامج النصية للاختبار من أجل تمرير بيانات متعددة إلى التطبيق في وقت التشغيل. إنها إستراتيجية تنفيذ تقوم تلقائيًا بتشغيل حالات الاختبار عدة مرات باستخدام قيم مختلفة. يسمى المفهوم الذي تم تحقيقه من خلال تحديد معلمات نصوص الاختبار اختبار يعتمد على البيانات.
نوع المعلمة في TestNG
لتوضيح عملية تحديد المعلمات بشكل أفضل، سنستعرض خيارات تحديد المعلمات في أحد أكثر الأطر شيوعًا لـ Selenium WebDriver — TestNG.
هناك طريقتان والتي من خلالها يمكننا تحقيق المعلمة في TestNG:
- مع مساعدة من شرح المعلمات و مبادئ السلوك TestNG XML ملف.
- مع مساعدة من DataProvider حاشية. ملاحظة.
يلخص الرسم البياني أعلاه التقسيم: يمكن تعريف المعلمات من ملف testng.xml على مستوى المجموعة أو الاختبار، بينما يمكن للمعلمة من موفر البيانات أن تقبل Method و ITestContext كحجة مستقلة. فلندرسها بالتفصيل.
شرح المعلمات في TestNG
شرح المعلمات في TestNG هي طريقة تُستخدم لتمرير القيم إلى دوال الاختبار كوسائط باستخدام ملف XML. قد يُطلب من المستخدمين تمرير هذه القيم إلى دوال الاختبار أثناء التشغيل. يمكن استخدام طريقة التعليق التوضيحي @Parameters في أي دالة تحتوي على التعليقات التوضيحية @Test أو @Before أو @After أو @Factory.
شرح المعلمات باستخدام Testng.xml
اختر استخدام المعلمات باستخدام التعليقات التوضيحية عندما لا ترغب في التعامل مع التعقيد ويكون عدد مجموعات الإدخال صغيرًا.
دعونا نرى كيف يعمل هذا.
سيناريو الاختبار
الخطوة 1) قم بتشغيل المتصفح وانتقل إلى Google.com
الخطوة 2) أدخل كلمة البحث
الخطوة 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 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 جناح (ملاحظة: جناح)
يمكن تحديد المعلمات على مستويين:
- مستويات الأجنحة — المعايير داخل
<suite>علامة TestNG ملف XML عبارة عن معلمات على مستوى المجموعة. - مستوى الاختبار — المعايير داخل
<test>علامة TestNG ملف XML عبارة عن معلمات على مستوى الاختبار.
إليكم نفس الاختبار مع معلمات على مستوى المجموعة:
NOTE: إذا كان اسم المعامل متطابقًا على مستوى المجموعة ومستوى الاختبار، فإن معامل مستوى الاختبار له الأولوية على معامل مستوى المجموعة. في هذه الحالة، تشترك جميع الفئات داخل مستوى الاختبار في المعامل المُعدَّل، بينما تستمر الفئات خارج مستوى الاختبار في استخدام معامل مستوى المجموعة.
فحص الجهاز
العدد رقم 1: يؤدي وجود قيمة معلمة في ملف testng.xml لا يمكن تحويل نوعها إلى معلمة طريقة الاختبار المقابلة إلى ظهور خطأ.
خذ بعين الاعتبار المثال التالي:
هنا، تساوي سمة "المؤلف" 'Guru99'، وهو عبارة عن سلسلة نصية، بينما تتوقع طريقة الاختبار المقابلة قيمة عددية صحيحة، لذلك يتم طرح استثناء.
العدد رقم 2: لا توجد قيمة مقابلة لـ @Parameters في ملف testng.xml.
يمكنك حل هذه المشكلة عن طريق إضافة @Optional تعليق توضيحي إلى المعلمة المقابلة في طريقة الاختبار.
العدد رقم 3: تريد اختبار قيم متعددة لنفس المعلمة باستخدام ملف testng.xml.
باختصار، هذا غير ممكن. يمكنك استخدام عدة معلمات مختلفة، لكن كل معلمة لا تقبل إلا قيمة واحدة. هذا يمنع تضمين القيم مباشرةً في البرنامج النصي، ويحافظ على إمكانية إعادة استخدام الكود - اعتبره ملف تهيئة للبرنامج النصي. إذا كنت بحاجة إلى قيم متعددة لمعلمة واحدة، فاستخدم موفر بيانات (DataProvider) بدلاً من ذلك.
مزود البيانات في TestNG
مزود البيانات في TestNG هي طريقة تُستخدم عندما يحتاج المستخدم إلى تمرير معلمات معقدة. يجب إنشاء المعلمات المعقدة من Java يمكن تمرير الكائنات المعقدة، أو الكائنات من ملفات الخصائص، أو الكائنات من قاعدة البيانات، عبر دالة موفر البيانات. هذه الدالة مُعَلَّمة بالتعليق التوضيحي @DataProvider، وتُعيد مصفوفة من الكائنات.
المعلمات باستخدام Dataprovider
يُعدّ استخدام التعليق التوضيحي @Parameters سهلاً، ولكن لاختبار مجموعات بيانات متعددة، نحتاج إلى استخدام موفر بيانات.
لملء آلاف نماذج الويب باستخدام إطار الاختبار الخاص بنا، نحتاج إلى منهجية مختلفة يمكنها توفير مجموعة بيانات كبيرة جدًا في تدفق تنفيذ واحد.
يتم تحقيق هذا المفهوم القائم على البيانات من خلال @DataProvider تعليق توضيحي في TestNG.
لديها واحد فقط السمة، 'الاسم'إذا لم تحدد سمة الاسم، فسيكون اسم موفر البيانات هو نفسه اسم الطريقة المقابلة.
يقوم مزود البيانات بإرجاع ثنائي الأبعاد Java موضوع يتم استدعاء دالة الاختبار M مرة لمصفوفة كائنات بحجم M×N. على سبيل المثال، إذا أعاد موفر البيانات مصفوفة من كائنات بحجم 2×3، فسيتم استدعاء حالة الاختبار المقابلة مرتين مع 3 معلمات في كل مرة.
مثال كامل
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 إلى @اختبار حاشية. ملاحظة.
Code مثال
معلمة 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 نوعين من المعلمات.
الأسلوب — إذا كان نفسه يجب أن يتصرف موفر البيانات بشكل مختلف باختلاف طرق الاختبار، استخدم معلمة الطريقة.
في المثال التالي:
- نتحقق مما إذا كان اسم الطريقة هو 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" } }; } } }
هنا هو الإخراج:
ITestContext — يمكن استخدام هذا لإنشاء معلمات مختلفة لحالات الاختبار بناءً على المجموعات.
في الحياة الواقعية، يمكنك استخدام ITestContext لتغيير قيم المعلمات بناءً على أساليب الاختبار أو المضيفين أو تكوينات الاختبار.
في مثال الكود التالي:
- لدينا مجموعتان، أ و ب
- يتم تعيين كل طريقة اختبار لمجموعة
- إذا كانت قيمة المجموعة هي 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 بتحويل كل صف إلى استدعاء اختبار واحد.
- أضف التبعية. تضمن
org.apache.poi:poi-ooxmlفي مافن الخاص بك أو Gradle بناء. الـooxmlيتعامل البرنامج مع تنسيق .xlsx؛ عاديpoiيقرأ فقط ملفات .xls القديمة. - أنشئ المصنف. ضع صف العناوين في الصف 0 وحالة اختبار واحدة لكل صف أسفله، مع عمود واحد لكل وسيطة من وسائط طريقة الاختبار.
- اقرأ الورقة في مصفوفة. قم بتحديد حجم Object[][] بناءً على عدد الصفوف والخلايا بحيث يتم التقاط الصفوف الجديدة دون تغييرات في التعليمات البرمجية.
- أعده إلى المورد. يبقى توقيع طريقة الاختبار كما هو تمامًا كما كان من قبل.
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 السمة الموضحة سابقاً.

















