2009-03-20 20 views
18

Vorremmo eseguire alcuni dei nostri test ciascuno contro un insieme di valori di dati, verificando che le stesse condizioni valgano per ciascuna. I dati sono attualmente memorizzati in file flat o in semplici fogli di calcolo Excel.È possibile passare i parametri a TestNG DataProvider?

Il mio primo pensiero è stato quello di creare un DataProvider TestNG che caricava i dati dal file e può essere utilizzato per chiamare il metodo di test una volta per ogni valore di dati. Il mio problema è che test diversi devono caricare i dati da file diversi e non sembra esserci alcun modo per inviare un parametro al DataProvider. Qualcuno sa se questo è possibile?

Idealmente, vorrei il mio codice di simile al seguente (esempio semplificato):

public class OddTest { 
    @DataProvider(name = "excelLoader") 
    public Iterator<Object[]> loadExcelData(String fileName) { 
     ... 
    } 

    @Test(dataProvider = "excelLoader" dataProviderParameters = { "data.xls" }) 
    public void checkIsOddWorks(int num) 
     assertTrue(isOdd(num)); 
    } 
} 

risposta

14

Tratto da the TestNG docs:

Se dichiarate la vostra @DataProvider come prendere una java.lang.reflect.Method come primo parametro , TestNG passerà il metodo di prova corrente per questo primo parametro. Ciò è particolarmente utile quando diversi metodi di test utilizzano lo stesso @DataProvider e si desidera che restituisca valori diversi a seconda del metodo di test per il quale fornisce i dati.

Ad esempio, il codice seguente stampa il nome del metodo di prova all'interno del suo @DataProvider:

@DataProvider(name = "dp") 
public Object[][] createData(Method m) { 
    System.out.println(m.getName()); // print test method name 
    return new Object[][] { new Object[] { "Cedric" }}; 
} 

@Test(dataProvider = "dp") 
    public void test1(String s) { 
} 

@Test(dataProvider = "dp") 
    public void test2(String s) { 
} 

e saranno pertanto visualizzazione:

test1 
test2 

Questo può anche essere combinato con la soluzione fornita desolat per determinare i dati dal contesto e il metodo di conseguenza:

@DataProvider(name = "dp") 
    public Object[][] foodp(ITestContext ctx, Method method) { 
     // ... 
    } 
1

La risposta di yshua è un po 'limitante perché devi ancora eseguire l'hardcode dei percorsi di file all'interno del tuo fornitore di dati. Questo significa che dovresti cambiare il codice sorgente e poi ricompilarlo per eseguire nuovamente il test. Ciò annulla lo scopo dell'utilizzo di file XML per configurare l'esecuzione di test.

Una soluzione migliore, decisamente più hacky, sarebbe quella di creare un metodo @test fittizio che viene eseguito prima della suite, prende i percorsi dei file come parametri e salva queste informazioni all'interno della classe che ospita questi metodi di test.

Questa soluzione non è perfetta, ma fino a quando TestNG consente un migliore passaggio dei parametri (Forse questo è cambiato) questo potrebbe essere fattibile per le vostre esigenze.

+0

si potrebbe iniettare sia '' ITestContext' e method' (vedere la parte inferiore della risposta di "user64051") ed entrambi determinare i dati forniti dai parametri _AND_ metodi privati. Funziona nella versione attuale e sembra che abbia già funzionato in 5.14.x. –

17

È possibile accedere a tutti i parametri definiti nel DataProvider utilizzando TestNG's dependency injection capabilies. Questo è un esempio FornitoreDati ha bisogno del parametro "test_param":

@DataProvider(name = "usesParameter") 
public Object[][] provideTestParam(ITestContext context) { 
    String testParam = context.getCurrentXmlTest().getParameter("test_param"); 
    return new Object[][] {{ testParam }}; 
} 

Ciò richiede "test_param" da definire in voi suite.xml:

<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" > 
<suite name="suite"> 
    <parameter name="test_param" value="foo" /> 
    <test name="tests"> 
     <classes> 
      ... 
     </classes> 
    </test> 
</suite> 

Vedere la TestNG JavaDoc per i dettagli sulla classe ITestContext.

+0

Buona idea, ma ho provato questo e non ha funzionato per me. Penso che potrebbe essere perché sto usando testng all'interno del plugin Maven surefire. – Jared

+1

per me funziona con surefire 2.12 –

0

da aggiungere alla mia risposta sopra, ecco il codice completo di come si può fare usando EasyTest quadro:

@RunWith(DataDrivenTestRunner.class) 
public class MyTestClass { 

@Test 
@DataLoader(filePaths={myTestFile.xls}, loaderType=LoaderType.EXCEL) 
public void testFirstMethod(@Param() 
Map<String, Object> inputData) { 
    System.out.print("Executing testFirstMethod:"); 
    System.out.println("library Id : " + inputData.get("LibraryId")); 

} 

@Test 
@DataLoader(filePaths={mySecondTestFile.xls}, loaderType=LoaderType.EXCEL) 
public void testSecondMethod(@Param(name="input") 
MyClassObject inputData) { 
    System.out.print("Executing testSecondMethod:"); 
    System.out.println("library Id : " + inputData.get("LibraryId")); 

} 

E così via. Se vuoi sapere di più su come l'annotazione @DataLoader lavora in EasyTest, guardare il seguente: https://github.com/EaseTech/easytest/wiki/EasyTest-:-Loading-Data-using-Excel

noti che è possibile utilizzare XML, Excel, CSV o il proprio loader personalizzato per caricare i dati e tutti possono essere utilizzato nella stessa classe di test in una volta come mostrato in questo esempio: https://github.com/EaseTech/easytest/blob/master/src/test/java/org/easetech/easytest/example/TestCombinedLoadingAndWriting.java

Spero sia stato utile.

+0

Si dovrebbe aggiungere questo alla tua altra risposta piuttosto che come una completamente nuova, o almeno eliminare la risposta precedente. E come ci ha accennato @AndrewBarber, dovresti chiarire che questo è il tuo progetto. – forresthopkinsa

1

Un modo più generico di fare questo sarebbe quello di utilizzare il groups annotazioni di costruire un elenco personalizzato di valori:

@DataProvider(name = "excelLoader") 
public Object[][] createData(Method m) { 
    ArrayList<Object[]> excelFiles = new ArrayList<Object[]>; 
    // iterate over all the groups listed in the annotation 
    for (String excelFile : ((Test) m.getAnnotation(Test.class)).groups()) { 
     // add each to the list 
     excelFiles.add(new Object[] { excelFile }); 
    } 
    // convert the list to an array 
    return excelFiles.toArray(new Object[excelFiles.size()]); 
} 

@Test(dataProvider = "excelLoader", groups = { "data1", "data2" }) 
public void test1(String excelFile) { 
    // we will test "data1.xls" and "data2.xls" in this test 
    String testExcelFile = excelFile + ".xls"; 
} 

@Test(dataProvider = "excelLoader", groups = { "data2", "data3" }) 
public void test2(String excelFile) { 
    // we will test "data2.xls" and "data3.xls" in this test 
    String testExcelFile = excelFile + ".xls"; 
} 

In alternativa si potrebbe anche creare la propria classe di annotazione che prende in elementi personalizzati in modo che si potrebbe fare qualcosa di più simile a:

@Retention(java.lang.annotation.RetentionPolicy.RUNTIME) 
@Target({METHOD, TYPE, CONSTRUCTOR}) 
public @interface FilesToTest { 
    public String[] value() default {}; 
} 

@DataProvider(name = "excelLoader") 
public Object[][] createData(Method m) { 
    ArrayList<Object[]> excelFiles = new ArrayList<Object[]>; 
    // iterate over all the groups listed in the annotation 
    for (String excelFile : ((FilesToTest) m.getAnnotation(FilesToTest.class)).value()) { 
     // add each to the list 
     excelFiles.add(new Object[] { excelFile }); 
    } 
    // convert the list to an array 
    return excelFiles.toArray(new Object[excelFiles.size()]); 
} 

@Test(dataProvider = "excelLoader") 
@FilesToTest({ "data1.xls", "data2.xls" }) 
public void myTest(String excelFile) { 
    // we will test "data1.xls" and "data2.xls" in this test 
} 
+0

Soluzione piacevole ed elegante, in particolare il secondo snippet di codice. Grazie. – Stuart

Problemi correlati