Fornitore di dati in TestNG: Selenium Esempio di parametrizzazione
โก Riepilogo intelligente
Parametrizzazione in Selenium esegue ripetutamente un singolo metodo di test su diversi set di dati, trasformando uno script in una copertura basata sui dati. TestNG offre due meccanismi per questo: l'annotazione @Parameters supportata da testng.xml e l'annotazione @DataProvider che restituisce un array di oggetti bidimensionale.

Quando creiamo software, vogliamo sempre che funzioni correttamente con diversi set di dati. Quando si tratta di analisi Verificare un singolo set di dati con quel software non รจ sufficiente. Dobbiamo verificare che il sistema accetti ogni combinazione che dovrebbe supportare. Per questo, dobbiamo parametrizzare i nostri script di test. Ed รจ qui che entra in gioco la parametrizzazione.
Parametrizzazione in Selenium
Parametrizzazione in Selenium รจ un processo per parametrizzare gli script di test al fine di passare piรน dati all'applicazione in fase di runtime. ร una strategia di esecuzione che esegue automaticamente i casi di test piรน volte utilizzando valori diversi. Il concetto ottenuto parametrizzando gli script di test viene chiamato Test guidati dai dati.
Tipo di parametrizzazione in TestNG
Per rendere piรน chiara la parametrizzazione, esamineremo le opzioni di parametrizzazione in uno dei framework piรน popolari per Selenium WebDriver โ TestNG.
Ci sono due strade con il quale possiamo ottenere la parametrizzazione in TestNG:
- Con l'aiuto del Annotazione dei parametri e TestNG XML file.
- Con l'aiuto del DataProvider annotazione.
Il diagramma sopra riassume la suddivisione: i parametri da testng.xml possono essere dichiarati a livello di suite o di test, mentre un parametro da un DataProvider puรฒ accettare Method and ITestContext come argomento a sรฉ stante. Analizziamoli nel dettaglio.
Parametri Annotazione in TestNG
Parametri Annotazione in TestNG ร un metodo utilizzato per passare valori ai metodi di test come argomenti tramite un file .xml. Agli utenti potrebbe essere richiesto di passare i valori ai metodi di test durante l'esecuzione. Il metodo di annotazione @Parameters puรฒ essere utilizzato in qualsiasi metodo che abbia l'annotazione @Test, @Before, @After o @Factory.
Annotazione dei parametri con Testng.xml
Scegli la parametrizzazione tramite annotazioni quando non vuoi avere a che fare con la complessitร e il numero di combinazioni di input รจ ridotto.
Vediamo come funziona.
Scenario di prova
Passo 1) Avvia il browser e vai a Google.com
Passo 2) Inserisci una parola chiave di ricerca
Passo 3) Verifica che il valore inserito corrisponda al valore fornito dai nostri dati di test.
Passo 4) Ripetere i passaggi 2 e 3 finchรฉ non sono stati inseriti tutti i valori.
| Autore della prova | Chiave di ricerca |
|---|---|
| Guru99 | India |
| Krishna | USA |
| Bupesh | Cina |
Ecco un esempio di come farlo senza parametri:
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 Nota del 4: Tre righe nella versione originale di questo esempio non vengono piรน compilate o sono deprecate sulla versione corrente Selenium stampa. System.setProperty("webdriver.gecko.driver", โฆ) รจ superfluo da Selenium Dal 4.6 in poi perchรฉ Selenium Il gestore risolve automaticamente il file binario del driver. implicitlyWait(10, TimeUnit.SECONDS) il sovraccarico รจ stato rimosso in Selenium 4 e sostituito da implicitlyWait(Duration.ofSeconds(10)). getAttribute() รจ stato deprecato in Selenium 4.27, quindi la lettura di una casella di testo utilizza getDomProperty("value")Ciascuno degli esempi seguenti applica le stesse tre correzioni.
Esamina l'esempio qui sopra e immagina quanto diventi complesso il codice quando questo viene ripetuto per tre combinazioni di input.
Ora parametrizziamolo usando TestNGPer farlo, รจ necessario:
- Creare un file XML che memorizzerร i parametri
- Nel test, aggiungi l'annotazione @Parameters
Ecco il codice completo.
Livello di prova 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>
ParametroConTestNGFile 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)); } }
Per eseguire lo script, seleziona il file XML ed eseguilo come TestNG on.
Fai clic con il pulsante destro del mouse sul file .xml -> Esegui come -> TestNG Suite (Nota: Suite)
I parametri possono essere definiti a due livelli:
- Livello suite โ i parametri all'interno del
<suite>tag del TestNG I file XML contengono parametri a livello di suite. - Livello di prova โ i parametri all'interno del
<test>tag del TestNG Il file XML contiene i parametri a livello di test.
Ecco lo stesso test con parametri a livello di suite:
NOTA: Se il nome del parametro รจ lo stesso a livello di suite e a livello di test, il parametro a livello di test ha la precedenza su quello a livello di suite. In tal caso, tutte le classi all'interno di quel livello di test condividono il parametro sovrascritto, mentre le classi al di fuori di quel livello di test continuano a utilizzare il parametro a livello di suite.
Troubleshooting
Problema n. 1: Un valore di parametro in testng.xml che non puรฒ essere convertito nel tipo corrispondente al parametro del metodo di test genera un errore.
Considera il seguente esempio:
Qui, l'attributo 'autore' รจ uguale a 'Guru'99', che รจ una stringa, mentre il metodo di test corrispondente si aspetta un valore intero, quindi viene generata un'eccezione.
Problema n. 2: I tuoi @Parameters non hanno un valore corrispondente in testng.xml.
Puoi risolvere questo aggiungendo il @Annotazione facoltativa al parametro corrispondente nel metodo di prova.
Problema n. 3: Si desidera testare piรน valori dello stesso parametro utilizzando testng.xml.
La risposta semplice รจ che non รจ possibile. ร possibile avere piรน parametri diversi, ma ciascun parametro puรฒ contenere un solo valore. Questo impedisce di inserire valori fissi nello script e mantiene il codice riutilizzabile: pensatelo come un file di configurazione per il vostro script. Se avete bisogno di piรน valori per un singolo parametro, utilizzate un DataProvider.
Fornitore di dati in TestNG
Fornitore di dati in TestNG รจ un metodo utilizzato quando un utente deve passare parametri complessi. I parametri complessi devono essere creati da Java โ Il metodo del provider di dati puรฒ passare oggetti complessi, oggetti provenienti da file di proprietร o oggetti da un database. Il metodo รจ annotato con @DataProvider e restituisce un array di oggetti.
Parametri che utilizzano il provider di dati
L'annotazione @Parameters รจ semplice, ma per eseguire test con piรน set di dati รจ necessario utilizzare un Data Provider.
Per compilare migliaia di moduli web utilizzando il nostro framework di test, abbiamo bisogno di una metodologia diversa, in grado di fornire un set di dati molto ampio in un singolo flusso di esecuzione.
Questo concetto basato sui dati viene realizzato tramite @DataProvider annotazione in TestNG.
Ne ha solo uno attributo, 'nome'Se non si specifica l'attributo name, il nome del DataProvider รจ uguale al nome del metodo corrispondente.
Un fornitore di dati restituisce bidimensionale Java oggetto al metodo di test, e il metodo di test viene richiamato M volte per un array di oggetti MรN. Ad esempio, se il DataProvider restituisce un array di 2ร3 oggetti, il caso di test corrispondente viene richiamato 2 volte con 3 parametri ogni volta.
Esempio completo
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" } }; } }
Richiama DataProvider da una classe diversa
Per impostazione predefinita, un DataProvider risiede nella stessa classe del metodo di test o nella sua classe base. Per posizionarlo in un'altra classe, rendere il metodo del provider di dati statico e aggiungi l'attributo dataProviderClass ai @Test annotazione.
Code Esempio
TestClass ParametroDataproviderWithClassLevel.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" } }; } }
Tipi di parametri nel provider di dati
Il metodo DataProvider supporta due tipi di parametri.
Metodo โ se il stesso Il comportamento di DataProvider dovrebbe variare a seconda del metodo di test utilizzato; si consiglia di utilizzare il parametro Method.
Nell'esempio seguente:
- Verifichiamo se il nome del metodo รจ testMethodA
- In caso affermativo, restituisci un insieme di valori
- Altrimenti restituisci un altro set di valori
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" } }; } } }
Ecco l'output:
ITestContext โ questo puรฒ essere utilizzato per creare parametri diversi per i casi di test in base ai gruppi.
Nella pratica, รจ possibile utilizzare ITestContext per variare i valori dei parametri in base ai metodi di test, agli host o alle configurazioni di test.
Nell'esempio di codice seguente:
- Abbiamo 2 gruppi, A e B
- Ciascun metodo di prova รจ assegnato a un gruppo
- Se il valore del gruppo รจ A, viene restituito un set di dati
- Se il valore del gruppo รจ B, viene restituito un altro set di dati.
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; } }
Nota: Se esegui il TestNG Se si richiama direttamente la classe, viene prima chiamato il provider di dati, e quest'ultimo non puรฒ leggere le informazioni sui gruppi perchรฉ questi non sono ancora disponibili. Richiamando la classe tramite testng.xml, le informazioni sui gruppi diventano disponibili tramite ITestContext. Utilizzare il seguente XML per eseguire il 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>
Entrambi i meccanismi sono stati ora illustrati, quindi la questione pratica รจ quale dei due scegliere.
@Parameters vs @DataProvider: quale utilizzare?
I due approcci non sono intercambiabili. La decisione dipende da quante combinazioni di valori sono necessarie per un test e da dove provengono tali valori.
| Criterio | @Parameters + testng.xml | @DataProvider |
|---|---|---|
| Valori per parametro | Esattamente uno | Righe illimitate |
| Fonte di dati | Testo statico nel file XML | Java codice, Excel, CSV, database, API |
| Tipi supportati | Valori convertiti dal tipo Stringa | Qualsiasi Java oggetto |
| Invocazioni di test | Una volta per configurazione | Una volta per riga di dati |
| La modifica dei dati richiede | Modifica del file XML | Modifica del codice sorgente, spesso senza ricompilazione |
| piรน adatto a | Ambiente e valori di configurazione come browser, URL, credenziali | Test basati sui dati su numerose combinazioni di input. |
In pratica, la maggior parte delle suite utilizza entrambi i metodi: @Parameters contiene le impostazioni dell'ambiente che rimangono costanti durante l'esecuzione, mentre @DataProvider fornisce i dati aziendali variabili. Quando il set di dati supera la capacitร di un array predefinito, il passo successivo consiste nel leggerlo da un foglio di calcolo.
Come leggere i dati di test da un file Excel utilizzando DataProvider
Gli array hardcoded smettono di scalare una volta che i tester che non scrivono Java รจ necessario mantenere i dati. Spostando le righe in un foglio di calcolo si separano i dati di test dalla logica di test, che รจ la forma pratica di test guidati dai datiApache POI legge la cartella di lavoro e il DataProvider converte ogni riga in un'invocazione di test.
- Aggiungi la dipendenza. Includere
org.apache.poi:poi-ooxmlnel tuo Maven o Gradle costruire. Ilooxmlartefatto gestisce il formato .xlsx; semplicepoilegge solo i file .xls legacy. - Crea la cartella di lavoro. Inserisci la riga di intestazione nella riga 0 e un caso di test per riga sotto di essa, con una colonna per ogni argomento del metodo di test.
- Carica il foglio in un array. Dimensiona l'oggetto Object[][] in base al numero di righe e celle, in modo che le nuove righe vengano rilevate senza modifiche al codice.
- Restituiscilo al fornitore. La firma del metodo di test rimane esattamente come prima.
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; } }
Suggerimento: Bando getStringCellValue() solo sulle celle formattate come testo. Una cella numerica genera IllegalStateException, che รจ l'errore piรน comune quando un foglio di calcolo contiene ID o importi. Utilizzare un DataFormatter per leggere ogni tipo di cella come stringa o attivare cell.getCellType() e convertire esplicitamente.
Con i dati esternalizzati, l'aggiunta di altri cento casi di test diventa una modifica del foglio di calcolo piuttosto che una modifica del codice e lo stesso fornitore puรฒ alimentare diverse classi di test attraverso il dataProviderClass attributo mostrato in precedenza.
















