2009-03-20 9 views
18

Nous souhaitons effectuer chacun de nos tests en fonction d'un ensemble de valeurs de données, en vérifiant que les mêmes conditions sont vraies pour chacune d'elles. Les données sont actuellement stockées dans des fichiers plats ou dans de simples feuilles de calcul Excel. Ma première pensée était de créer un DataProvider TestNG qui chargerait les données du fichier et serait utilisé pour appeler la méthode de test une fois pour chaque valeur de données. Mon problème est que différents tests doivent charger des données à partir de différents fichiers et il ne semble pas y avoir moyen d'envoyer un paramètre au DataProvider. Est-ce que quelqu'un sait si c'est possible?Possibilité de passer des paramètres à TestNG DataProvider?

Idéalement, je voudrais que mon code pour ressembler (exemple simplifié) suivant:

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)); 
    } 
} 

Répondre

14

Extrait du the TestNG docs:

Si vous déclarez votre @DataProvider en prenant un java.lang.reflect.Method comme premier paramètre , TestNG passera la méthode de test actuelle pour ce premier paramètre. Ceci est particulièrement utile lorsque plusieurs méthodes de test utilisent le même @DataProvider et que vous souhaitez qu'il renvoie des valeurs différentes en fonction de la méthode de test pour laquelle il fournit des données.

Par exemple, le code suivant imprime le nom de la méthode d'essai à l'intérieur de son @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) { 
} 

et sera donc l'affichage:

test1 
test2 

Cela peut également être combiné avec la solution fournie par desolat pour déterminer des données à partir du contexte et de la méthode en conséquence:

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

La réponse de yshua est un peu restrictive, car vous devez encore coder en dur les chemins de fichier à l'intérieur de votre fournisseur de données. Cela signifie que vous devrez modifier le code source, puis recompiler pour réexécuter le test. Cela annule le but de l'utilisation de fichiers XML pour configurer le test. Un meilleur, certainement plus hacky, kludge d'une solution serait de créer une méthode fictive @test qui s'exécute avant la suite, prend vos chemins de fichiers en tant que paramètres et enregistre ces informations dans la classe abritant ces méthodes de test.

Cette solution n'est pas parfaite, mais jusqu'à ce que TestNG permette un meilleur passage des paramètres (cela a peut-être changé) cela pourrait être viable pour vos besoins.

+0

on pourrait injecter la fois '' ITestContext' et method' (voir le bas de la réponse de « user64051 ») et à la fois déterminer les données fournies à partir des paramètres suite _ET_ méthodes. Cela fonctionne dans la version actuelle et il semble que cela a déjà fonctionné dans 5.14.x. –

17

Vous pouvez accéder à tous les paramètres définis dans votre DataProvider à l'aide de TestNG's dependency injection capabilies. Ceci est un exemple DataProvider dans le besoin du paramètre « test_param »:

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

Cela nécessite « test_param » à définir en vous 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> 

Voir la TestNG JavaDoc pour plus de détails sur la classe ITestContext.

+0

Bonne idée, mais j'ai essayé ça et ça n'a pas marché pour moi. Je pense que c'est parce que j'utilise testng dans le plugin maven surefire. – Jared

+1

pour moi cela fonctionne avec surefire 2.12 –

0

Pour ajouter à ma réponse ci-dessus, voici le code complet de la façon dont vous pouvez le faire en utilisant Framework EasyTest:

@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")); 

} 

Et ainsi de suite. Si vous voulez en savoir plus sur la façon dont l'annotation @DataLoader fonctionne dans EasyTest, regardez ce qui suit: https://github.com/EaseTech/easytest/wiki/EasyTest-:-Loading-Data-using-Excel

Notez que vous pouvez utiliser XML, Excel, CSV ou votre chargeur sur mesure pour charger les données et tous peuvent être utilisé dans la même classe de test à la fois comme indiqué dans cet exemple: https://github.com/EaseTech/easytest/blob/master/src/test/java/org/easetech/easytest/example/TestCombinedLoadingAndWriting.java

J'espère que c'était utile.

+0

Vous devriez ajouter ceci à votre autre réponse plutôt que comme une entièrement nouvelle, ou au moins supprimer votre réponse précédente. Et comme @AndrewBarber mentionné ici, vous devez vraiment faire comprendre que c'est votre projet. – forresthopkinsa

1

Une façon plus générique de le faire serait d'utiliser l'annotation groups pour construire une liste personnalisée des valeurs:

@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"; 
} 

Sinon, vous pouvez créer votre propre classe d'annotation qui prend des éléments personnalisés afin que vous pourriez faire quelque chose comme:

@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

Belle solution élégante, en particulier le deuxième extrait de code. Merci. – Stuart

Questions connexes