可以将参数传递给 TestNG DataProvider?

Posted

技术标签:

【中文标题】可以将参数传递给 TestNG DataProvider?【英文标题】:Possible to pass parameters to TestNG DataProvider? 【发布时间】:2010-10-14 13:37:21 【问题描述】:

我们希望针对一组数据值分别运行一些测试,验证每个测试的条件是否相同。数据当前存储在平面文件或简单的 Excel 电子表格中。

我的第一个想法是创建一个 TestNG DataProvider,它会从文件中加载数据,并用于为每个数据值调用一次测试方法。我的问题是不同的测试需要从不同的文件加载数据,并且似乎没有任何方法可以将参数发送到 DataProvider。 有人知道这是否可行吗?

理想情况下,我希望我的代码如下所示(简化示例):

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

【问题讨论】:

【参考方案1】:

取自the TestNG docs:

如果您将@DataProvider 声明为将java.lang.reflect.Method 作为第一个参数,TestNG 将传递此第一个参数的当前测试方法。当多个测试方法使用相同的 @DataProvider 并且您希望它根据它提供数据的测试方法返回不同的值时,这特别有用。

例如,以下代码在其@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) 

因此会显示:

test1
test2

这也可以与desolat提供的方案结合,根据上下文判断数据,相应的方法:

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

【讨论】:

【参考方案2】:

您可以使用 TestNG's dependency injection capabilies 访问 DataProvider 中所有已定义的参数。这是一些需要“test_param”参数的示例 DataProvider:

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

这需要在您suite.xml 中定义“test_param”:

<!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>

有关 ITestContext 类的详细信息,请参阅TestNG JavaDoc。

【讨论】:

好主意,但我试过了,但它对我不起作用。我认为这可能是因为我在 maven surefire 插件中使用了 testng。 有人能告诉我解决方案吗***.com/questions/52753698/…【参考方案3】:

更通用的方法是使用groups 注释来构建自定义值列表:

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

或者,您也可以创建自己的注释类来接受自定义元素,以便您可以做更多类似的事情:

@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

【讨论】:

不错,优雅的解决方案,尤其是第二个代码 sn-p。谢谢。【参考方案4】:

为了补充我上面的答案,下面是使用 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"));


等等。 如果您想了解更多关于 @DataLoader 注解在 EasyTest 中的工作原理,请查看以下内容:https://github.com/EaseTech/easytest/wiki/EasyTest-:-Loading-Data-using-Excel

请注意,您可以使用 XML、Excel、CSV 或您自己的自定义加载器来加载数据,并且可以同时在同一个测试类中使用,如本例所示:https://github.com/EaseTech/easytest/blob/master/src/test/java/org/easetech/easytest/example/TestCombinedLoadingAndWriting.java

希望对你有用。

【讨论】:

您应该将此添加到您的其他答案中,而不是作为一个全新的答案,或者至少删除您之前的答案。正如@AndrewBarber 在那里提到的那样,您应该明确表明这是您的项目。【参考方案5】:

yshua 的回答有点局限,因为您仍然需要对数据提供程序中的文件路径进行硬编码。这意味着您必须更改源代码,然后重新编译才能重新运行测试。这违背了使用 XML 文件配置测试运行的目的。

一个更好的、绝对更老套的解决方案是创建一个在套件之前运行的虚拟@test 方法,将您的文件路径作为参数并将此信息保存在包含这些测试方法的类中。

这个解决方案并不完美,但在 TestNG 允许更好的参数传递之前(也许这已经改变),这可能满足您的需求。

【讨论】:

可以同时注入ITestContextMethod(参见“user64051”答案的底部),并且都可以从套件参数 方法中确定提供的数据。这在当前版本中有效,看起来它已经在 5.14.x 中有效。

以上是关于可以将参数传递给 TestNG DataProvider?的主要内容,如果未能解决你的问题,请参考以下文章

如何将参数传递给 Cucumber 中的@before 方法?

cucumber + java:将步骤1中返回的参数传递给第2步

如何将参数传递给 Java 线程?

是否可以将查询参数传递给 Django % url % 模板标签?

将参数传递给 Gulp 任务

将参数传递给路由保护