可以将参数传递给TestNG DataProvider吗?

时间:2009-03-20 14:53:29

标签: testng data-driven-tests

我们希望针对一组数据运行我们的一些测试,验证每个测试的条件是否相同。数据当前存储在平面文件或简单的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));
    }
}

5 个答案:

答案 0 :(得分:17)

您可以使用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

答案 1 :(得分:16)

取自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 :(得分: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
}

答案 3 :(得分:1)

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

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

这个解决方案并不完美,但是直到TestNG允许更好的参数传递(可能这已经改变),这可能适合您的需求。

答案 4 :(得分:0)

要添加上面的答案,请参阅使用EasyTest Framework完成代码的完整代码:

@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

我希望它很有用。