Постачальник даних у TestNG: Selenium Приклад параметризації
⚡ Розумний підсумок
Параметризація в Selenium багаторазово запускає один метод тестування на різних наборах даних, перетворюючи один скрипт на покриття на основі даних. TestNG пропонує два механізми для цього: анотацію @Parameters, що підтримується testng.xml, та анотацію @DataProvider, яка повертає двовимірний масив об'єктів.
Створюючи програмне забезпечення, ми завжди хочемо, щоб воно коректно працювало з різними наборами даних. Коли справа доходить до Тестування цього програмного забезпечення, перевірки одного набору даних недостатньо. Нам потрібно переконатися, що система приймає кожну комбінацію, яку вона повинна підтримувати. Для цього нам потрібно параметризувати наші тестові скрипти. Саме тут і знадобиться параметризація.
Параметризація в Selenium
Параметризація в Selenium це процес параметризації тестових сценаріїв для передачі кількох даних у програму під час виконання. Це стратегія виконання, яка автоматично запускає тестові випадки кілька разів, використовуючи різні значення. Називається концепція, досягнута шляхом параметризації тестових сценаріїв Тестування на основі даних.
Тип параметризації в TestNG
Щоб зробити параметризацію зрозумілішою, ми розглянемо варіанти параметризації в одному з найпопулярніших фреймворків для Selenium Вебдрайвер — TestNG.
Існує два способи за допомогою якого ми можемо досягти параметризації в TestNG:
- За допомогою Анотація параметрів і TestNG XML файлу.
- За допомогою DataProvider анотація
Наведена вище діаграма підсумовує розподіл: параметри з testng.xml можна оголосити на рівні набору або тесту, тоді як параметр з DataProvider може приймати Method та ITestContext як окремий аргумент. Давайте детально розглянемо їх.
Параметри Анотація в TestNG
Параметри Анотація в TestNG – це метод, що використовується для передачі значень тестовим методам як аргументів за допомогою файлу .xml. Користувачам може знадобитися передавати значення тестовим методам під час виконання. Метод анотації @Parameters можна використовувати в будь-якому методі, що має анотацію @Test, @Before, @After або @Factory.
Анотація параметрів за допомогою Testng.xml
Оберіть параметризацію за допомогою анотацій, коли ви не хочете мати справу зі складністю, а кількість вхідних комбінацій невелика.
Давайте подивимося, як це працює.
Сценарій тесту
Крок 1) Запустіть браузер і перейдіть до Google.com
Крок 2) Введіть ключове слово для пошуку
Крок 3) Перевірте, чи введене значення збігається зі значенням, наданим нашими тестовими даними.
Крок 4) Повторюйте кроки 2 та 3, доки не будуть введені всі значення
| Автор тесту | SearchKey |
|---|---|
| Guru99 | Індія |
| Krishna | USA |
| Бхупеш | Китай |
Ось приклад того, як це зробити без параметрами:
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
<?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>
ParameterWithTestNGФайл 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-файл – це параметри тестового рівня.
Ось той самий тест з параметрами рівня набору:
ПРИМІТКА: Якщо назва параметра однакова на рівні набору та рівні тестування, параметр рівня тестування має перевагу над параметром рівня один набору. У такому випадку всі класи всередині цього рівня тестування використовують перевизначений параметр, а класи поза цим рівнем тестування продовжують використовувати параметр рівня набору.
Пошук і усунення несправностей
Випуск №1: Значення параметра в testng.xml, яке не може бути перетворене на відповідний параметр методу тестування, викликає помилку.
Розглянемо наступний приклад:
Тут атрибут 'author' дорівнює 'Guru99', що є рядком, тоді як відповідний метод тестування очікує ціле значення, тому виникає виняток.
Випуск №2: Ваші @Parameters не мають відповідного значення в testng.xml.
Ви можете вирішити це, додавши @Додаткова анотація до відповідного параметра в методі випробування.
Випуск №3: Ви хочете перевірити кілька значень одного й того ж параметра за допомогою testng.xml.
Проста відповідь полягає в тому, що цього зробити неможливо. Ви можете мати кілька різних параметрів, але кожен параметр може містити лише одне значення. Це запобігає жорсткому впровадженню значень у скрипт і забезпечує можливість повторного використання коду — уявіть собі це як конфігураційний файл для вашого скрипта. Якщо вам потрібно кілька значень для одного параметра, використовуйте DataProvider.
Постачальник даних в TestNG
Постачальник даних в TestNG – це метод, який використовується, коли користувачеві потрібно передати складні параметри. Складні параметри потрібно створити з Java — складні об'єкти, об'єкти з файлів властивостей або об'єкти з бази даних можуть бути передані методом постачальника даних. Метод позначено анотацією @DataProvider і повертає масив об'єктів.
Параметри за допомогою Dataprovider
Анотація @Parameters проста, але для тестування з кількома наборами даних нам потрібно використовувати постачальника даних.
Щоб заповнити тисячі веб-форм за допомогою нашої тестової системи, нам потрібна інша методологія, яка може надати дуже великий набір даних за один процес виконання.
Ця концепція, заснована на даних, досягається завдяки @DataProvider анотація в TestNG.
Він має лише один атрибут, «ім'я»Якщо атрибут name не вказано, ім'я постачальника даних (DataProvider) буде таким самим, як і ім'я відповідного методу.
Постачальник даних повертає двовимірний Java об'єкт до тестового методу, і тестовий метод викликається M разів для масиву об'єктів розміром M×N. Наприклад, якщо DataProvider повертає масив об'єктів 2×3, відповідний тестовий випадок викликається 2 рази з 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 з іншого класу
За замовчуванням, DataProvider знаходиться в тому ж класі, що й тестовий метод, або в його базовому класі. Щоб розмістити його в іншому класі, зробіть метод постачальника даних статичний і додайте атрибут dataProviderClass до @Тест анотація
Code Приклад
TestClass ParameterDataproviderWithClassLevel.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) повинен поводитися по-різному для різних методів тестування, використовуйте параметр Method.
У наступному прикладі:
- Ми перевіряємо, чи назва методу — 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 для зміни значень параметрів залежно від методів тестування, хостів або конфігурацій тестування.
У наступному прикладі коду:
- У нас є 2 групи, А та Б
- Кожний метод тестування призначений для групи
- Якщо значення групи дорівнює 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: який з них використовувати
Ці два підходи не є взаємозамінними. Рішення зводиться до того, скільки комбінацій значень потрібно для тесту та звідки ці значення походять.
| критерій | @Параметри + testng.xml | @DataProvider |
|---|---|---|
| Значення для кожного параметра | Рівно один | Необмежена кількість рядків |
| Джерело даних | Статичний текст у XML-файлі | Java код, Excel, CSV, база даних, API |
| Підтримувані типи | Типи значень з рядка (String) | будь-який Java об'єкт |
| Виклики тестів | Один раз на конфігурацію | Один раз на рядок даних |
| Зміна даних вимагає | Редагування XML-файлу | Редагування вихідного коду, часто без перекомпіляції |
| Найкраще підходить для | Значення середовища та конфігурації, такі як браузер, URL, облікові дані | Тестування на основі даних для багатьох комбінацій вхідних даних |
На практиці більшість пакетів використовують обидва: @Parameters містить налаштування середовища, які залишаються незмінними протягом усього запуску, а @DataProvider надає змінні бізнес-дані. Коли набір даних перевищує жорстко закодований масив, наступним кроком є зчитування його з електронної таблиці.
Як зчитати тестові дані з файлу Excel за допомогою DataProvider
Жорстко закодовані масиви перестають масштабуватися, як тільки тестувальники, які не пишуть Java потрібно зберігати дані. Переміщення рядків у електронну таблицю відокремлює тестові дані від тестової логіки, що є практичною формою тестування на основі данихApache POI зчитує книгу, а DataProvider перетворює кожен рядок на один тестовий виклик.
- Додайте залежність. Include
org.apache.poi:poi-ooxmlу вашому Maven або Gradle побудувати. Theooxmlартефакт обробляє формат .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 атрибут, показаний раніше.

















