Dostawca danych w TestNG: Selenium Przykład parametryzacji
⚡ Inteligentne podsumowanie
Parametryzacja w Selenium uruchamia tę samą metodę testową wielokrotnie na różnych zestawach danych, zmieniając jeden skrypt w obszar objęty badaniem opartym na danych. TestNG oferuje dwa mechanizmy do tego celu: adnotację @Parameters opartą na pliku testng.xml oraz adnotację @DataProvider zwracającą dwuwymiarową tablicę obiektów.

Tworząc oprogramowanie, zawsze zależy nam na tym, aby działało ono poprawnie z różnymi zestawami danych. Jeśli chodzi o testowanie W przypadku tego oprogramowania sprawdzenie pojedynczego zestawu danych nie wystarczy. Musimy zweryfikować, czy system akceptuje każdą kombinację, którą ma obsługiwać. W tym celu musimy sparametryzować nasze skrypty testowe. Właśnie tutaj pojawia się parametryzacja.
Parametryzacja w Selenium
Parametryzacja w Selenium to proces parametryzacji skryptów testowych w celu przekazania wielu danych do aplikacji w czasie wykonywania. Jest to strategia wykonania, która automatycznie uruchamia przypadki testowe wiele razy, używając różnych wartości. Koncepcja osiągnięta poprzez parametryzację skryptów testowych nazywa się Testowanie oparte na danych.
Rodzaj parametryzacji w TestNG
Aby ułatwić zrozumienie parametryzacji, omówimy opcje parametryzacji w jednym z najpopularniejszych frameworków Selenium WebDriver — TestNG.
Tam są dwie drogi dzięki któremu możemy osiągnąć parametryzację w TestNG:
- Z pomocą Adnotacja parametrów i TestNG XML plik.
- Z pomocą Dostawca danych adnotacja.
Powyższy diagram podsumowuje podział: parametry z pliku testng.xml można zadeklarować na poziomie zestawu lub testu, podczas gdy parametr z DataProvider może akceptować Method oraz ITestContext jako osobny argument. Przyjrzyjmy się im szczegółowo.
Parametry Adnotacja w TestNG
Parametry Adnotacja w TestNG to metoda służąca do przekazywania wartości do metod testowych jako argumentów za pomocą pliku .xml. Użytkownicy mogą być zobowiązani do przekazywania wartości do metod testowych w czasie wykonywania. Metoda adnotacji @Parameters może być używana w dowolnej metodzie z adnotacją @Test, @Before, @After lub @Factory.
Adnotacja parametrów za pomocą Testng.xml
Wybierz parametryzację za pomocą adnotacji, jeśli nie chcesz mieć do czynienia ze złożonością, a liczba kombinacji wejściowych jest niewielka.
Zobaczmy, jak to działa.
Scenariusz testowy
Krok 1) Uruchom przeglądarkę i przejdź do Google.com
Krok 2) Wprowadź słowo kluczowe wyszukiwania
Krok 3) Sprawdź, czy wprowadzona wartość jest taka sama, jak wartość podana w naszych danych testowych
Krok 4) Powtarzaj kroki 2 i 3, aż wprowadzisz wszystkie wartości.
| Autor testu | Klucz wyszukiwania |
|---|---|
| Guru99 | India |
| Krishna | USA |
| Bhupesz | Chiny |
Oto przykład, jak to zrobić bez parametry:
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 Uwaga 4: Trzy wiersze w oryginalnej wersji tego przykładu nie kompilują się już lub są obecnie przestarzałe Selenium Wydania. System.setProperty("webdriver.gecko.driver", …) jest niepotrzebne od Selenium 4.6 i dalej, ponieważ Selenium Menedżer automatycznie rozwiązuje plik binarny sterownika. implicitlyWait(10, TimeUnit.SECONDS) przeciążenie zostało usunięte w Selenium 4 i zastąpiony przez implicitlyWait(Duration.ofSeconds(10)). getAttribute() został wycofany w Selenium 4.27, więc czytanie pola tekstowego używa getDomProperty("value")Każdy przykład poniżej stosuje te same trzy poprawki.
Przyjrzyj się powyższemu przykładowi i wyobraź sobie, jak skomplikowany staje się kod, gdy powtórzysz go dla trzech kombinacji danych wejściowych.
Teraz sparametryzujmy to za pomocą TestNGAby to zrobić, musisz:
- Utwórz plik XML, w którym będą przechowywane parametry
- W teście dodaj adnotację @Parameters
Oto kompletny kod.
Poziom testowy 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>
ParametrZTestNGPlik 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)); } }
Aby uruchomić skrypt, wybierz plik XML i uruchom go jako TestNG na.
Kliknij prawym przyciskiem myszy plik .xml -> Uruchom jako -> TestNG Apartament (Uwaga: Apartament)
Parametry można definiować na dwóch poziomach:
- Poziom apartamentu — parametry wewnątrz
<suite>tag TestNG Pliki XML zawierają parametry na poziomie pakietu. - Poziom testowy — parametry wewnątrz
<test>tag TestNG Pliki XML zawierają parametry na poziomie testu.
Oto ten sam test z parametrami na poziomie pakietu:
UWAGA: Jeśli nazwa parametru jest taka sama na poziomie zestawu i testu, parametr poziomu testu ma pierwszeństwo przed parametrem poziomu zestawu. W takim przypadku wszystkie klasy na tym poziomie testu współdzielą nadpisany parametr, a klasy spoza tego poziomu testu nadal korzystają z parametru poziomu zestawu.
Rozwiązywanie problemów
Kwestia nr 1: Wartość parametru w pliku testng.xml, której nie można rzutować na parametr odpowiadającej metody testowej, powoduje błąd.
Rozważ następujący przykład:
Tutaj atrybut „autor” jest równy „Guru99', który jest ciągiem znaków, podczas gdy odpowiadająca mu metoda testowa oczekuje wartości całkowitej, więc zgłaszany jest wyjątek.
Kwestia nr 2: Twoje @Parameters nie mają odpowiadającej wartości w testng.xml.
Możesz rozwiązać ten problem, dodając @Opcjonalna adnotacja do odpowiedniego parametru w metodzie testowej.
Kwestia nr 3: Chcesz przetestować wiele wartości tego samego parametru za pomocą pliku testng.xml.
Prosta odpowiedź brzmi: nie da się tego zrobić. Można mieć wiele różnych parametrów, ale każdy parametr może zawierać tylko jedną wartość. Zapobiega to zakodowaniu wartości na stałe w skrypcie i umożliwia wielokrotne wykorzystanie kodu — pomyśl o tym jak o pliku konfiguracyjnym skryptu. Jeśli potrzebujesz wielu wartości dla jednego parametru, użyj dostawcy danych.
Dostawca danych w TestNG
Dostawca danych w TestNG to metoda używana, gdy użytkownik musi przekazać złożone parametry. Złożone parametry muszą zostać utworzone z Java — obiekty złożone, obiekty z plików właściwości lub obiekty z bazy danych mogą być przekazywane przez metodę dostawcy danych. Metoda jest adnotowana @DataProvider i zwraca tablicę obiektów.
Parametry przy użyciu dostawcy danych
Adnotacja @Parameters jest prosta, ale aby przeprowadzić test na wielu zestawach danych, musimy użyć Dostawcy danych.
Aby wypełnić tysiące formularzy internetowych przy użyciu naszego środowiska testowego, potrzebujemy innej metodologii, która pozwoli na dostarczenie bardzo dużego zestawu danych w ramach jednego przebiegu wykonywania.
Koncepcję opartą na danych udało się osiągnąć dzięki @Dostawca danych adnotacja w TestNG.
Ma tylko jeden atrybut, 'nazwa'. Jeśli nie określisz atrybutu name, nazwa DataProvider będzie taka sama jak nazwa odpowiadającej jej metody.
Dostawca danych zwraca dwuwymiarowy Java przedmiot do metody testowej, a metoda testowa jest wywoływana M razy dla tablicy obiektów M×N. Na przykład, jeśli DataProvider zwróci tablicę 2×3 obiektów, odpowiadający jej przypadek testowy jest wywoływany 2 razy z 3 parametrami za każdym razem.
Kompletny przykład
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" } }; } }
Wywołaj DataProvider z innej klasy
Domyślnie DataProvider znajduje się w tej samej klasie co metoda testowa lub w jej klasie bazowej. Aby umieścić go w innej klasie, należy utworzyć metodę DataProvider. statyczny i dodaj atrybut klasa dostawcy danych do @Test adnotacja.
Code Przykład
TestClass ParametrDataproviderWithClassLevel.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" } }; } }
Typy parametrów w dostawcy danych
Metoda DataProvider obsługuje dwa typy parametrów.
Metoda wykonania — jeśli taki sam DataProvider powinien zachowywać się inaczej dla różnych metod testowych, należy użyć parametru Method.
W poniższym przykładzie:
- Sprawdzamy, czy nazwa metody to testMethodA
- Jeśli tak, zwróć jeden zestaw wartości
- W przeciwnym razie zwróć inny zestaw wartości
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" } }; } } }
Oto wynik:
Kontekst testowy — można go używać do tworzenia różnych parametrów dla przypadków testowych w oparciu o grupy.
W rzeczywistości ITestContext można wykorzystać do zmieniania wartości parametrów na podstawie metod testowych, hostów lub konfiguracji testów.
W poniższym przykładzie kodu:
- Mamy 2 grupy: A i B
- Każda metoda badawcza jest przypisana do grupy
- Jeśli wartością grupy jest A, zwracany jest jeden zestaw danych
- Jeśli wartością grupy jest B, zwracany jest inny zestaw danych
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; } }
Uwaga: Jeśli uruchomisz TestNG Klasa jest bezpośrednio wywoływana, najpierw wywołuje dostawcę danych, a dostawca nie może odczytać informacji o grupach, ponieważ grupy nie są jeszcze dostępne. Wywołanie klasy za pośrednictwem pliku testng.xml udostępnia informacje o grupach za pośrednictwem ITestContext. Użyj poniższego kodu XML, aby uruchomić test:
<!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>
Obydwa mechanizmy są już omówione, więc pojawia się praktyczne pytanie: który z nich wybrać?
@Parameters kontra @DataProvider: Którego użyć?
Te dwa podejścia nie są zamienne. Decyzja sprowadza się do tego, ile kombinacji wartości jest potrzebnych w teście i skąd te wartości pochodzą.
| Kryterium | @Parameters + testng.xml | @Dostawca danych |
|---|---|---|
| Wartości na parametr | Dokładnie jeden | Nieograniczona liczba wierszy |
| Źródło danych | Tekst statyczny w pliku XML | Java kod, Excel, CSV, baza danych, API |
| Obsługiwane typy | Wartości typu rzutowane z String | Każdy Java przedmiot |
| Wywołania testowe | Raz na konfigurację | Raz na wiersz danych |
| Zmiana danych wymaga | Edycja pliku XML | Edycja kodu źródłowego, często bez ponownej kompilacji |
| Najlepiej nadaje się do | Wartości środowiskowe i konfiguracyjne, takie jak przeglądarka, URL, referencje | Testowanie oparte na danych w wielu kombinacjach danych wejściowych |
W praktyce większość pakietów korzysta z obu: @Parameters przechowuje ustawienia środowiska, które pozostają niezmienne w trakcie przebiegu, a @DataProvider dostarcza zmienne dane biznesowe. Gdy zestaw danych przekroczy limit zakodowanej tablicy, kolejnym krokiem jest odczytanie go z arkusza kalkulacyjnego.
Jak odczytać dane testowe z pliku Excel za pomocą DataProvider
Zakodowane na stałe tablice przestają się skalować, gdy testerzy, którzy nie piszą Java konieczność utrzymania danych. Przeniesienie wierszy do arkusza kalkulacyjnego oddziela dane testowe od logiki testowej, co jest praktyczną formą testowanie oparte na danychApache POI odczytuje skoroszyt, a DataProvider konwertuje każdy wiersz na jedno wywołanie testu.
- Dodaj zależność. Zawierać
org.apache.poi:poi-ooxmlw Twoim Maven lub Gradle zbudować. Tenooxmlartefakt obsługuje format .xlsx; zwykłypoiodczytuje tylko starsze pliki .xls. - Utwórz skoroszyt. Umieść wiersz nagłówka w wierszu 0, a w każdym wierszu poniżej umieść jeden przypadek testowy, przy czym na każdy argument metody testowej umieść jedną kolumnę.
- Wczytaj arkusz do tablicy. Zmień rozmiar obiektu [][] na podstawie liczby wierszy i komórek, aby nowe wiersze były pobierane bez zmian w kodzie.
- Zwróć go od dostawcy. Podpis metody testowej pozostaje dokładnie taki sam jak poprzednio.
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; } }
💡 Wskazówka: Numer Telefonu getStringCellValue() tylko w komórkach sformatowanych jako tekst. Komórka numeryczna generuje IllegalStateException, co jest najczęstszą awarią, gdy arkusz kalkulacyjny zawiera identyfikatory lub kwoty. Użyj DataFormatter aby odczytać każdy typ komórki jako ciąg lub włączyć cell.getCellType() i konwertować jawnie.
Dzięki eksternalizacji danych dodawanie setek kolejnych przypadków testowych staje się edycją arkusza kalkulacyjnego, a nie zmianą kodu, a ten sam dostawca może przekazywać wiele klas testowych przez dataProviderClass atrybut pokazany wcześniej.
















