TestNG的详细教程请看链接:https://blog.csdn.net/df0128/article/details/83243822
此处需要用到注解@DataProvider
来进行传参,
如下定义了一个测试用例,名为TestNgLearn1
,其有两个参数传入,param1
和param2
,都是int
型。其标注@Test
内部含有一个dataProvider = "provideNumbers"
即为指明其参数来源,其中provideNumbers
为参数来源的那个方法的名称。
除了测试用例外还定义了一个方法叫做provideData
,其标注为@DataProvider
,即说明此方法是一个参数提供方法,其包含多个参数值可供指定,下面分别说明:
name
指定该参数提供者的名称,其他测试用例可以通过该名称调用此方法,其实如果此属性不指定的话,会默认将方法名称作为该数据提供者的名称,即其他用例可以通过方法名称来调用此方法;
如下name="provideNumbers"
中的provideNumbers
即为设定的参数提供者的名称,此名称和测试方法TestNgLearn1
注解中需要的数据提供者名称一致,如下是一个最简单的范例:
public class TestCase1 {
@DataProvider(name = "provideNumbers")
public Object[][] provideData() {
return new Object[][] { { 10, 20 }, { 100, 110 }, { 200, 210 } };
}
@Test(dataProvider = "provideNumbers", groups= {"gp1"})
public void TestNgLearn1(int param1, int param2) {
System.out.println("this is TestNG test case1, and param1 is:"+param1+"; param2 is:"+param2);
Assert.assertFalse(false);
}
}
此处数据提供者返回的的内容必须为Object[][]
,即一个二维数组,此处要注意,如上面的例子返回了三组参数,故用例应当会被执行三次,即如下结果:
this is TestNG test case1, and param1 is:10; param2 is:20
this is TestNG test case1, and param1 is:100; param2 is:110
this is TestNG test case1, and param1 is:200; param2 is:210
PASSED: TestNgLearn1(10, 20)
PASSED: TestNgLearn1(100, 110)
PASSED: TestNgLearn1(200, 210)
===============================================
Default test
Tests run: 3, Failures: 0, Skips: 0
===============================================
如上结果符合预期,运行三次,三组值都运行了一次;
@DataProvider
除了必须定义name外,还有两个值可以指定,一个是indices
,此值指定返回的参数组中的第几个会被使用,编号从0开始,如下范例指定了indices= {1}
,name执行结果应当只有第二组参数值,代码如下:
public class TestCase1 {
@DataProvider(name = "provideNumbers",indices= {1})
public Object[][] provideData() {
return new Object[][] { { 10, 20 }, { 100, 110 }, { 200, 210 } };
}
@Test(dataProvider = "provideNumbers", groups= {"gp1"})
public void TestNgLearn1(int param1, int param2) {
System.out.println("this is TestNG test case1, and param1 is:"+param1+"; param2 is:"+param2);
Assert.assertFalse(false);
}
}
运行结果如下:
this is TestNG test case1, and param1 is:100; param2 is:110
PASSED: TestNgLearn1(100, 110)
===============================================
Default test
Tests run: 1, Failures: 0, Skips: 0
===============================================
如上结果符合预期,只使用了三组参数中的第二组,即编号为1的那一组;注意编号不要超出你返回的列表的大小;
此参数意思是是否并发执行,其值可为true
或者false
,默认为false
,如果为true
则会并发执行,范例如下:
public class TestCase1 {
@DataProvider(name = "provideNumbers",parallel=true)
public Object[][] provideData() {
return new Object[][] { { 10, 20 }, { 100, 110 }, { 200, 210 } };
}
@Test(dataProvider = "provideNumbers", groups= {"gp1"})
public void TestNgLearn1(int param1, int param2) {
System.out.println("this is TestNG test case1, and param1 is:"+param1+"; param2 is:"+param2);
Assert.assertFalse(false);
}
}
结果如下:
this is TestNG test case1, and param1 is:200; param2 is:210
this is TestNG test case1, and param1 is:10; param2 is:20
this is TestNG test case1, and param1 is:100; param2 is:110
PASSED: TestNgLearn1(100, 110)
PASSED: TestNgLearn1(200, 210)
PASSED: TestNgLearn1(10, 20)
===============================================
Default test
Tests run: 3, Failures: 0, Skips: 0
===============================================
因为范例运行较快,而此处TestNG并未打印很详细的东西,所以看不出来是并发,但是如果是用一个运行较慢的用例来验证,就可以看出来了。
除了可以从@DataProvider
传入参数外,还可以通过testng.xml中传入参数;
此方法需要在用例上除了@Test
外还要添加注解@Parameters
,同时xml中要有parameter
标签来输入对应的参数,如下范例所示:
测试用例:
public class ParameterSample {
@Test
@Parameters({ "dbconfig", "poolsize" })
public void test(String dbconfig, int poolsize)
{
System.out.println("dbconfig : " + dbconfig);
System.out.println("poolsize : " + poolsize);
}
}
xml:
<suite name="Suite" parallel="none">
<test name="Test">
<parameter name="dbconfig" value="db.properties" />
<parameter name="poolsize" value="10" />
<classes>
<class name="com.demo.test.testng.ParameterSample"/>
classes>
test>
suite>
运行xml结果如下:
dbconfig : db.properties
poolsize : 10
===============================================
Suite
Total tests run: 1, Failures: 0, Skips: 0
===============================================
前面都是传参的基本用法,下面介绍一些传参的稍微高级的用法;
@DataProvider
传入对象代码如下
public class ParameterSample {
@Test(dataProvider = "dbconfig")
public void testConnection(Map<String, String> map) {
for (Map.Entry<String, String> entry : map.entrySet())
{
System.out.println("[Key] : " + entry.getKey() + " [Value] : " + entry.getValue());
}
}
@DataProvider(name = "dbconfig")
public Object[][] provideDbConfig() {
Map<String, String> map = readDbConfig();
return new Object[][] { { map } };
}
public Map<String, String> readDbConfig()
{
Map<String, String> map = new HashMap<String, String>();
try {
map.put("jdbc.driver", "com.mysql.jdbc.Driver");
map.put("jdbc.url", "jdbc:mysql://localhost:3306/test");
map.put("jdbc.username", "root");
map.put("jdbc.password", "root");
} catch (Exception e) {
e.printStackTrace();
}
return map;
}
}
运行结果:
[Key] : jdbc.password [Value] : root
[Key] : jdbc.username [Value] : root
[Key] : jdbc.url [Value] : jdbc:mysql://localhost:3306/test
[Key] : jdbc.driver [Value] : com.mysql.jdbc.Driver
PASSED: testConnection({jdbc.password=root, jdbc.username=root, jdbc.url=jdbc:mysql://localhost:3306/test, jdbc.driver=com.mysql.jdbc.Driver})
===============================================
Default test
Tests run: 1, Failures: 0, Skips: 0
===============================================
不过这样的话就会只有一条用例了。
@DataProvider
分别对两个测试用例传参代码如下:
public class ParameterSample {
@Test(dataProvider = "dataProvider")
public void test1(int number, int expected) {
Assert.assertEquals(number, expected);
}
@Test(dataProvider = "dataProvider")
public void test2(String email, String expected) {
Assert.assertEquals(email, expected);
}
@DataProvider(name = "dataProvider")
public Object[][] provideData(Method method) {
Object[][] result = null;
if (method.getName().equals("test1")) {
result = new Object[][] {
{ 1, 1 }, { 200, 200 }
};
} else if (method.getName().equals("test2")) {
result = new Object[][] {
{ "[email protected]", "[email protected]" },
{ "[email protected]", "[email protected]" }
};
}
return result;
}
}
运行结果如下:
PASSED: test1(1, 1)
PASSED: test1(200, 200)
PASSED: test2("[email protected]", "[email protected]")
PASSED: test2("[email protected]", "[email protected]")
===============================================
Default test
Tests run: 4, Failures: 0, Skips: 0
===============================================
@DataProvider
被多个用例使用,但根据分组名称传递参数代码:
public class TestParameterDataProvider4 {
@Test(dataProvider = "dataProvider", groups = {"groupA"})
public void test1(int number) {
Assert.assertEquals(number, 1);
}
@Test(dataProvider = "dataProvider", groups = "groupB")
public void test2(int number) {
Assert.assertEquals(number, 2);
}
@DataProvider(name = "dataProvider")
public Object[][] provideData(ITestContext context) {
Object[][] result = null;
for (String group : context.getIncludedGroups()) {
System.out.println("group : " + group);
if ("groupA".equals(group)) {
result = new Object[][] { { 1 } };
break;
}
}
if (result == null) {
result = new Object[][] { { 2 } };
}
return result;
}
}
xml内容:
<suite name="Suite" parallel="false">
<test name="Test">
<groups>
<run>
<include name="groupA"/>
run>
groups>
<classes>
<class name="com.demo.test.testng.TestParameterDataProvider4"/>
classes>
test>
suite>
运行xml结果如下:
group : groupA
===============================================
Suite
Total tests run: 1, Failures: 0, Skips: 0
===============================================
@DataProvider
返回迭代器public class ParameterSample1 {
@Test(dataProvider = "dp")
public void test(String str, Integer i)
{
System.out.println(str+i);
}
@DataProvider
public Iterator<Object[]> dp()
{
List<Object[]> objList = new ArrayList<Object[]>();
for(int i = 1; i < 5; i++)
{
objList.add(new Object[]{"第" + i + "名得分", new Integer(i) });
}
return objList.iterator();
}
}
执行结果:
第1名得分1
第2名得分2
第3名得分3
第4名得分4
PASSED: test("第1名得分", 1)
PASSED: test("第2名得分", 2)
PASSED: test("第3名得分", 3)
PASSED: test("第4名得分", 4)
===============================================
Default test
Tests run: 4, Failures: 0, Skips: 0
===============================================
public class ParameterSample1 {
@Test(dataProvider = "dp")
public void test(Demo demo)
{
System.out.println("我从myDataProvider仓库拿到了名字:" + demo.getName() + ";年龄:" + demo.getAge());
}
@DataProvider
public Iterator<Object[]> dp()
{
List<Demo> list = new ArrayList<Demo>();
Demo demo1 = new Demo();
demo1.setName("david");
demo1.setAge(19);
Demo demo2 = new Demo();
demo2.setName("sansa");
demo2.setAge(20);
list.add(demo1);
list.add(demo2);
List<Object[]> fArrList = new ArrayList<Object[]>();
for (Object f : list)
{
fArrList.add(new Object[] { f });
}
return fArrList.iterator();
}
}
Demo.java:
public class Demo {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
运行结果:
我从myDataProvider仓库拿到了名字:david;年龄:19
我从myDataProvider仓库拿到了名字:sansa;年龄:20
PASSED: test(com.demo.test.testng.Demo@6c49835d)
PASSED: test(com.demo.test.testng.Demo@56aac163)
===============================================
Default test
Tests run: 2, Failures: 0, Skips: 0
===============================================
在上面两个例子中,分别传入了Object[]和自定义对象的迭代器,内容都是从类内部直接写的,其实在实际应用中,对于同一条用例,不同入参的验证,在集成化的情况下大多会选择从文件读取,那么,只需要在上面的代码中加入读取文件的内容并组合的步骤即可;
其实从xml读取参数的方法比较死板,不如使用@DataProvider
灵活,实际应用中多用这个来进行全局参数的设定等;
这里介绍下如果想从xml读取参数来运行同一条用例的方法:
代码:
public class ParameterSample {
@Test
@Parameters({ "dbconfig", "poolsize" })
public void test(String dbconfig, int poolsize)
{
System.out.println("dbconfig : " + dbconfig);
System.out.println("poolsize : " + poolsize);
}
}
xml:
<suite name="Suite" parallel="none">
<test name="Test">
<parameter name="dbconfig" value="db.properties" />
<parameter name="poolsize" value="10" />
<classes>
<class name="com.demo.test.testng.ParameterSample">
<methods>
<include name="test" />
methods>
class>
classes>
test>
<test name="Test1">
<parameter name="dbconfig" value="db.properties1" />
<parameter name="poolsize" value="101" />
<classes>
<class name="com.demo.test.testng.ParameterSample">
<methods>
<include name="test" />
methods>
class>
classes>
test>
suite>
运行结果:
dbconfig : db.properties
poolsize : 10
dbconfig : db.properties1
poolsize : 101
===============================================
Suite
Total tests run: 2, Failures: 0, Skips: 0
===============================================
@DataProvider
在前面的例子中,测试用例和传参的方法都在同一个文件中,那么是否这两个可以不在一个类当中呢?答案是肯定的,只是需要在测试用例上添加dataProviderClass
属性即可,其指定的是@DataProvider
所在的class
,如下这个范例就是从其他类中传入@DataProvider
,代码如下:
测试用例类:
public class ParameterSample1 {
@Test(dataProvider = "data", dataProviderClass = ParameterSample.class)
public void getDataFromOtherClass(String name, int age)
{
System.out.println("name:"+name+"; age:"+age);
}
}
@DataProvider
类:
public class ParameterSample {
@DataProvider(name = "data",parallel=true)
public Object[][] data()
{
return new Object[][] { {"张三", 12}, {"李四", 13} };
}
运行测试用例结果如下:
name:张三; age:12
name:李四; age:13
PASSED: getDataFromOtherClass("张三", 12)
PASSED: getDataFromOtherClass("李四", 13)
===============================================
Default test
Tests run: 2, Failures: 0, Skips: 0
===============================================
需要注意的是此方式下,@DataProvider
就不能采用不加注解的方式了,必须要加此注解,还要指定名称,且名称必须和用例上那个调用名称相同;