0%

TestNG专题:参数化

传参的方式

TestNG 通常有两种传参的方法:

  • 在 XML 配置文件中添加参数,并通过 @Parameters 参数传入
  • 使用 @DataProvider 注解的方法返回测试参数。

前者适合添加少量参数,后者适合大量测试参数或数据的情况。

使用@Parameters传参

XML配置

要使用 @Parameters 传参,需要在 XML 配置文件中以 <parameter> 标签添加参数配置。

<parameter> 标签可以放在 <suite><test><classes><class> 等标签中,区别只是参数的作用域不同,内层的参数会覆盖外层同名参数。

当然可以配置多个参数,但参数间是相互独立的。可以仅传入一个参数,也可以一次传入多个参数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >

<suite name="@Test传参测试-单参">
<parameter name="param" value="suite传入的参数"/>
<parameter name="param2" value="suite传入的参数2"/>
<test name="单参:class传参测试">
<classes>
<class name="com.github.ericzong.param.SingleParamOnTestMethod">
<parameter name="param" value="class传入的参数"></parameter>
</class>
</classes>
</test>
<test name="单参:classes传参测试">
<classes>
<class name="com.github.ericzong.param.SingleParamOnTestMethod"/>
<parameter name="param" value="classes传入的参数"/>
</classes>
</test>
<test name="单参:test传参测试">
<parameter name="param" value="test传入的参数"/>
<classes>
<class name="com.github.ericzong.param.SingleParamOnTestMethod"/>
</classes>
</test>
<test name="单参:suite传参测试">
<classes>
<class name="com.github.ericzong.param.SingleParamOnTestMethod"/>
</classes>
</test>
</suite>

@Parameters注解@Test方法

@Parameters 中指定的参数名与 XML 配置文件是一一对应的,跟注解方法的形参名称无关。

毕竟,从反射的能力看,方法形参名通常是不能取得的。

1
2
3
4
5
6
7
public class MultiParamsOnTestMethod {
@Parameters({"param", "param2"})
@Test
public void testMultiParams(String p1, String p2) {
System.out.println("【@Test多参】param: " + p1 + "; param2: " + p2);
}
}

@Parameters注解@BeforeXxx/@AfterXxx方法

所有前后置处理器都可以使用 @Parameters 注解传参,这包括:

  • @BeforeSuite/@AfterSuite
  • @BeforeTest/@AfterTest
  • @BeforeGroups/@AfterGroups
  • @BeforeClass/@AfterClass
  • @BeforeMethod/@AfterMethod

【注意事项】
一旦使用了分组,那么 @BeforeXxx@AfterXxx 都需要指定分组,否则不会被执行。
一个技巧是在类上通过 @Test 设置 groups 统一指定分组。但是,这对 @BeforeGroups@AfterGroups 无效,需要额外指定——特别的,可以通过 groupsvalue 指定。

@Parameters注解Factory方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class ParamOnFactoryMethod {
private String data;

public ParamOnFactoryMethod(String data) {
this.data = data;
}

@Parameters("param")
@Factory
public Object[] createInstances(String param) {
Object[] instances = new ParamOnFactoryMethod[3];
for (int i = 0; i < 3; i++) {
instances[i] = new ParamOnFactoryMethod("【@Factory】实例" + i + ": " + param);
}

return instances;
}

@Test
public void testInstance() {
System.out.println(this.data);
}
}

@Parameters注解构造器

1
2
3
4
5
6
7
8
9
10
11
12
13
public class ParamOnConstructor {
private String name;

@Parameters({"param"})
public ParamOnConstructor(String name) {
this.name = name;
}

@Test
public void testConstructor() {
System.out.println("【构造器上@Parameters传参】" + this.name);
}
}

默认值

如果通过注解传入了参数,则当 XML 配置文件不配置参数,导致参数值缺失,则在用例执行时会抛出异常。

这意味着一旦使用 @Parameters 传参,则将不能再从类/方法执行测试用例,只能从 XML 配置文件执行。

但是,可以通过为参数指定默认值,使其可以从类/方法执行某种默认的测试行为。

1
2
3
4
5
6
7
public class OptionalParamMethod {
@Parameters({"param"})
@Test
public void testOptionalParam(@Optional("默认值") String data) {
System.out.println("【@Optional】" + data);
}
}

使用DataProvider传参

@Parameters 传参只适合参数较少的场景,当参数太多,或者说需要大量测试数据时,就需要用到“数据提供器(Data Provider)”。

Data Provider位于同个类

@Test 通过 dataProvider 指定数据提供器的名称,数据由 @DataProvider 注解的方法返回。两者通过数据提供器的名字关联,如果 @DataProvider 设置 name 属性则名称为该指定名,否则为被注解的方法名。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class DataProviderInSameClassTest {

@DataProvider(name = "data")
public Object[][] createData() {
return new Object[][]{ // 以二维数据返回
{"@DataProvider"}, // 每行为一组测试数据
{"位于同类中"} // 每组数据可以指定多个参数
};
}

@Test(dataProvider = "data")
public void test(String desc) {
System.out.println(desc);
}
}

Data Provider位于不同类

测试用例与数据提供器在同一类中,通过数据提供器名称关联是可行的。但是,如果不在同一类中,则还需要指定数据提供器所在的类——由 dataProviderClass 属性指定。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class DataProviderInOtherClassTest {
@Test(dataProvider = "data", dataProviderClass = Provider.class)
public void test(String desc) {
System.out.println(desc);
}
}

class Provider {
@DataProvider(name = "data")
private static Object[][] createData() {
// 注意:
// 1. 访问修饰符权限是任意的
// 2. 若为实例方法,则要求该类具有公有构造器
return new Object[][]{
{"@DataProvider"},
{"位于不同类中"}
};
}
}

如果数据提供器与测试用例在同一类中,则该测试类必然是可实例化的。因此,数据提供器无论声明为 static 与否都是可以的。另外,访问修饰符设置为 private 都没问题。

特殊的是,如果数据提供器与测试用例不在同一类中,则数据提供器所在的类不一定可实例化。因此,除非数据提供器方法声明为 static,否则必须确保其所在类从外部有可访问的构造器——不然,会报“找不到构造器”。

【最佳实践】@DataProvider 应总是声明为 static 的。

【扩展说明】
@Parameters 不能用在 @DataProvider 注解的方法上。推测原因大致有两个原因:

  • 数据提供器本身就是提供参数的,再传入就多此一举
  • 当需要鉴别具体是哪个测试方法调用了提供器时,需要传入 Method 进行判断,再传入其他参数会有歧义

小结

TestNG 有 @Parameters@DataProvider 两种传参方式。

@Parameters 适合传递少量参数,@DataProvider 适合传递大量测试数据的情况。

@Parameters 可以为各种前后置处理器、@Test@Factory 注解的方法及构造器传参。

@DataProvider 注解方法可与测试位于同一类中,也可以位于不同类中。要么该方法声明为 static,要么确保该类存在可访问的默认构造器。