DataProvider in TestNG: Selenium Parameteriseringsvoorbeeld
⚡ Slimme samenvatting
Parametrering in Selenium Voert één testmethode herhaaldelijk uit op verschillende datasets, waardoor één script datagestuurde dekking mogelijk maakt. TestNG biedt hiervoor twee mechanismen: de @Parameters-annotatie, ondersteund door testng.xml, en de @DataProvider-annotatie, die een tweedimensionale objectarray retourneert.
Bij het ontwikkelen van software willen we altijd dat deze correct werkt met verschillende datasets. Als het gaat om... het testen van Voor die software is het controleren van één enkele dataset niet voldoende. We moeten verifiëren dat het systeem elke combinatie accepteert die het zou moeten ondersteunen. Daarvoor moeten we onze testscripts parameteriseren. Dit is waar parameterisering om de hoek komt kijken.
Parametrering in Selenium
Parametrering in Selenium is een proces om de testscripts te parametriseren om tijdens runtime meerdere gegevens door te geven aan de applicatie. Het is een uitvoeringsstrategie waarbij testgevallen automatisch meerdere keren worden uitgevoerd met verschillende waarden. Het concept dat wordt bereikt door het parametriseren van de testscripts wordt genoemd Datagedreven testen.
Type parametrering in TestNG
Om parameterisering te verduidelijken, zullen we de parameteriseringsopties in een van de populairste frameworks voor Selenium WebDriver — TestNG.
Er zijn twee manieren waarmee we parametrisering kunnen bereiken TestNG:
- Met behulp van de Parameterannotatie en TestNG XML bestand.
- Met behulp van de Data provider annotatie.
Het bovenstaande diagram vat de splitsing samen: parameters uit testng.xml kunnen worden gedeclareerd op suite- of testniveau, terwijl een parameter van een DataProvider kan accepteren... Method en ITestContext als eigen argument. Laten we ze eens nader bekijken.
Parameters Annotatie in TestNG
Parameters Annotatie in TestNG Dit is een methode om waarden als argumenten door te geven aan testmethoden via een XML-bestand. Gebruikers moeten de waarden mogelijk tijdens de uitvoering aan de testmethoden doorgeven. De annotatiemethode `@Parameters` kan worden gebruikt in elke methode met de annotaties `@Test`, `@Before`, `@After` of `@Factory`.
Parameterannotatie met Testng.xml
Kies voor parameterisering met behulp van annotaties als u geen complexe situaties wilt meemaken en het aantal invoercombinaties klein is.
Laten we eens kijken hoe dit werkt.
Testscenario
Stap 1) Start de browser en ga naar Google.com
Stap 2) Voer een zoekwoord in
Stap 3) Controleer of de ingevoerde waarde overeenkomt met de waarde in onze testgegevens.
Stap 4) Herhaal stap 2 en 3 totdat alle waarden zijn ingevoerd.
| Auteur testen | Zoeksleutel |
|---|---|
| Guru99 | India |
| Krishna | USA |
| Bhupesh | China |
Hier volgt een voorbeeld van hoe je dat kunt doen. zonder parameters:
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 Opmerking voor 4: Drie regels in de oorspronkelijke versie van dit voorbeeld compileren niet meer of zijn verouderd in de huidige versie. Selenium releases. System.setProperty("webdriver.gecko.driver", …) is niet nodig vanaf Selenium 4.6 en verder omdat Selenium De manager lost het binaire stuurprogramma automatisch op. implicitlyWait(10, TimeUnit.SECONDS) overbelasting werd verwijderd in Selenium 4 en vervangen door implicitlyWait(Duration.ofSeconds(10)). getAttribute() werd afgekeurd in Selenium 4.27, dus het lezen van een tekstvak maakt gebruik van getDomProperty("value")Elk voorbeeld hieronder past dezelfde drie correcties toe.
Bestudeer het bovenstaande voorbeeld en bedenk hoe complex de code wordt als dit wordt herhaald voor drie verschillende invoercombinaties.
Laten we het nu parameteriseren met behulp van TestNGOm dat te doen, moet je het volgende doen:
- Maak een XML-bestand waarin de parameters worden opgeslagen
- Voeg in de test de annotatie @Parameters toe.
Hier is de volledige code.
Test niveau 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>
ParameterMetTestNGXML.java-bestand
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)); } }
Om het script uit te voeren, selecteer je het XML-bestand en voer je het uit als een TestNG op.
Klik met de rechtermuisknop op het .xml-bestand -> Uitvoeren als -> TestNG Suite (Opmerking: Suite)
Parameters kunnen op twee niveaus worden gedefinieerd:
- Suiteniveau — de parameters binnen de
<suite>tag van de TestNG XML-bestanden bevatten parameters op suite-niveau. - Test niveau — de parameters binnen de
<test>tag van de TestNG XML-bestanden bevatten parameters op testniveau.
Hier is dezelfde test met parameters op suite-niveau:
NOTITIE: Als de parameternaam op suite-niveau en testniveau hetzelfde is, heeft de parameter op testniveau voorrang boven die op suite-niveau. In dat geval delen alle klassen binnen dat testniveau de overschreven parameter, terwijl klassen buiten dat testniveau de parameter op suite-niveau blijven gebruiken.
Problemen oplossen
Probleem nr. 1: Een parameterwaarde in testng.xml die niet kan worden omgezet naar het overeenkomstige type van de parameter van de testmethode, veroorzaakt een fout.
Overweeg het volgende voorbeeld:
Hier is het attribuut 'author' gelijk aan 'Guru'99', wat een tekenreeks is, terwijl de bijbehorende testmethode een geheel getal verwacht, waardoor een uitzondering wordt gegenereerd.
Probleem nr. 2: Uw @Parameters hebben geen overeenkomstige waarde in testng.xml.
Je kunt dit oplossen door toe te voegen: @Optionele annotatie naar de overeenkomstige parameter in de testmethode.
Probleem nr. 3: Je wilt meerdere waarden van dezelfde parameter testen met behulp van testng.xml.
Het simpele antwoord is dat dit niet mogelijk is. Je kunt wel meerdere verschillende parameters hebben, maar elke parameter kan slechts één waarde bevatten. Dit voorkomt dat waarden in het script worden vastgelegd en zorgt ervoor dat de code herbruikbaar blijft – zie het als een configuratiebestand voor je script. Als je meerdere waarden voor één parameter nodig hebt, gebruik dan een DataProvider.
Gegevensprovider in TestNG
Gegevensprovider in TestNG Dit is een methode die wordt gebruikt wanneer een gebruiker complexe parameters moet doorgeven. Complexe parameters moeten worden aangemaakt vanuit Java — Complexe objecten, objecten uit eigenschappenbestanden of objecten uit een database kunnen worden doorgegeven via de data provider-methode. De methode is geannoteerd met @DataProvider en retourneert een array van objecten.
Parameters met behulp van Dataprovider
De @Parameters-annotatie is eenvoudig, maar om met meerdere datasets te testen, moeten we een Data Provider gebruiken.
Om duizenden webformulieren in te vullen met ons testframework, hebben we een andere methodologie nodig die een zeer grote dataset in één enkele uitvoeringsworkflow kan verwerken.
Dit datagestuurde concept wordt gerealiseerd door de @Data provider annotatie in TestNG.
Er is er maar één attribuut, 'naam'Als u het naamkenmerk niet opgeeft, is de naam van de DataProvider gelijk aan de naam van de corresponderende methode.
Een gegevensaanbieder retourneert een tweedimensionale Java object naar de testmethode, en de testmethode wordt M keer aangeroepen voor een array van M×N objecten. Als de DataProvider bijvoorbeeld een array van 2×3 objecten retourneert, wordt de bijbehorende testcase 2 keer aangeroepen met telkens 3 parameters.
Compleet voorbeeld
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" } }; } }
Roep DataProvider aan vanuit een andere klasse
Standaard bevindt een DataProvider zich in dezelfde klasse als de testmethode, of in de basisklasse ervan. Om deze in een andere klasse te plaatsen, moet u de DataProvider-methode aanpassen. statisch en voeg het attribuut toe dataProviderClass aan de @Toets annotatie.
Code Voorbeeld
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" } }; } }
Soorten parameters in Dataprovider
De DataProvider-methode ondersteunt twee soorten parameters.
Methode — als de dezelfde De DataProvider moet zich anders gedragen voor verschillende testmethoden; gebruik hiervoor de parameter Method.
In het volgende voorbeeld:
- We controleren of de methodenaam testMethodA is.
- Indien ja, retourneer één set waarden.
- Anders moet een andere set waarden worden geretourneerd.
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" } }; } } }
Dit is de uitvoer:
ITestContext — Dit kan worden gebruikt om verschillende parameters voor testgevallen te creëren op basis van groepen.
In de praktijk kun je ITestContext gebruiken om parameterwaarden te variëren op basis van testmethoden, hosts of testconfiguraties.
In het volgende codevoorbeeld:
- We hebben 2 groepen, A en B.
- Elke testmethode wordt toegewezen aan een groep
- Als de groepswaarde A is, wordt één dataset geretourneerd.
- Als de groepswaarde B is, wordt een andere dataset geretourneerd.
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; } }
Let op: Als je de TestNG Als de klasse rechtstreeks wordt aangeroepen, wordt eerst de data provider aangeroepen. De provider kan de groepsgegevens echter niet lezen omdat de groepen nog niet beschikbaar zijn. Door de klasse via testng.xml aan te roepen, worden de groepsgegevens beschikbaar via ITestContext. Gebruik de volgende XML om de test uit te voeren:
<!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>
Beide mechanismen zijn nu behandeld, dus de praktische vraag is welke je moet kiezen.
@Parameters versus @DataProvider: welke te gebruiken?
De twee benaderingen zijn niet uitwisselbaar. De keuze hangt af van hoeveel waardecombinaties een test nodig heeft en waar die waarden vandaan komen.
| Criterium | @Parameters + testng.xml | @Data provider |
|---|---|---|
| Waarden per parameter | Precies één | Onbeperkt aantal rijen |
| Databron | Statische tekst in het XML-bestand | Java code, Excel, CSV, database, API |
| Ondersteunde typen | Waarden gecast van String naar String | Elke Java object |
| Testoproepen | Eenmaal per configuratie | Eenmaal per gegevensrij |
| Het wijzigen van gegevens vereist | Het XML-bestand bewerken | Het bewerken van de broncode, vaak zonder hercompilatie. |
| Het meest geschikt voor: | Omgevings- en configuratiewaarden zoals browser, URL, referenties | Datagestuurd testen met veel verschillende inputcombinaties |
In de praktijk gebruiken de meeste softwarepakketten beide: @Parameters bevat de omgevingsinstellingen die constant blijven tijdens een run, en @DataProvider levert de wisselende bedrijfsgegevens. Wanneer de dataset te groot wordt voor een vastgelegde array, is de volgende stap het inlezen ervan uit een spreadsheet.
Hoe lees je testgegevens uit een Excel-bestand met behulp van DataProvider?
Hardcoded arrays schalen niet meer zodra testers die niet schrijven Java De gegevens moeten behouden blijven. Door de rijen naar een spreadsheet te verplaatsen, worden testgegevens gescheiden van testlogica, wat de praktische vorm is van datagedreven testenApache POI leest het werkblad en de DataProvider zet elke rij om in een testaanroep.
- Voeg de afhankelijkheid toe. omvatten
org.apache.poi:poi-ooxmlin uw Maven of Gradle bouw. Deooxmlartifact verwerkt het .xlsx-formaat; plainpoiKan alleen oudere .xls-bestanden lezen. - Maak het werkboek aan. Plaats de kopregel op rij 0 en daaronder één testgeval per rij, met één kolom per argument van de testmethode.
- Lees de gegevens in een array. Bepaal de grootte van het Object[][] op basis van het aantal rijen en cellen, zodat nieuwe rijen worden opgepakt zonder dat de code hoeft te worden aangepast.
- Stuur het terug naar de leverancier. De methodehandtekening van de test blijft exact hetzelfde als voorheen.
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; } }
💡Tip: Bel getStringCellValue() Alleen bij cellen die als tekst zijn opgemaakt. Een numerieke cel geeft een foutmelding. IllegalStateExceptionDit is de meest voorkomende fout wanneer een spreadsheet ID's of bedragen bevat. Gebruik een DataFormatter om elk celtype als een tekenreeks te lezen, of om dit in te schakelen cell.getCellType() en expliciet converteren.
Doordat de data extern beschikbaar is, wordt het toevoegen van honderd extra testgevallen een kwestie van een spreadsheetbewerking in plaats van een codewijziging, en dezelfde provider kan meerdere testklassen door de data heen sturen. dataProviderClass eerder getoonde eigenschap.

















