开始,我们先来思考一个场景,有一个测试类需要根据测试传入的N个参数进行N次执行。
方式一,可以直接在suite.xml中设置多个class,输入不同的参数执行测试用例
xml配置:
运行两次测试用例,第一次传key=“1”
,第二次传key=2
。
测试用例:
public class SimpleTest {
private static Logger logger = null;
@BeforeTest
public void setUp() {
logger = Logger.getLogger(WebTest.class);
}
@Parameters({"key"})
@Test
public void testServer(String key) {
logger.info(">>> "+key);
}
}
执行结果:
[WebTest] [INFO] >>> 1
[WebTest] [INFO] >>> 2
===============================================
Factory Test
Total tests run: 2, Failures: 0, Skips: 0
===============================================
从执行结果上看,测试用例确实使用了不同参数运行了两次,但是这里有明显的缺点:
,非常冗余和不好管理方式二,使用
@Factory
来配置工厂类来动态传入不同参数运行同一个测试用例
预执行的Test:
public class WebTest {
private int m_numberOfTimes;
private static Logger logger = null;
public WebTest(int numberOfTimes) {
m_numberOfTimes = numberOfTimes;
}
@BeforeTest
public void setUp() {
logger = Logger.getLogger(WebTest.class);
}
@Test
public void testServer() {
logger.info(">>> "+m_numberOfTimes);
}
}
需要多次执行testServer,输出从0~2的值,既m_numberOfTimes
依次取值0,1,2输出,我们使用Factory
来调用这个测试类:
public class WebTestFactory {
@Factory
public Object[] createInstance() {
Object[] result = new Object[3];
for (int i = 0; i < 3; i++) {
result[i] = new WebTest(i);
}
return result;
}
}
上面用Factory
注释createInstance,返回Object
类型数组,循环生成了三个WebTest
的对象赋值其中,然后在xml
中调用这个class类:
结果输出:
[WebTest] [INFO] >>> 2
[WebTest] [INFO] >>> 1
[WebTest] [INFO] >>> 0
===============================================
Factory Test
Total tests run: 3, Failures: 0, Skips: 0
===============================================
看到这里,仔细的同学可能会想,你这createInstance
什么鬼,循环三次还不是写死,哪来的动态?确实,我们来稍微修改下:
public class WebTestFactory {
@Parameters({"key"})
@Factory
public Object[] createInstance(String value) {
Integer num = Integer.valueOf(value);
Object[] result = new Object[num];
for (int i = 0; i < num; i++) {
result[i] = new WebTest(i);
}
return result;
}
}
修改完后,取xml
中配置参数key的值传入createInstance
,比如现在我们想输出0~4,只要改下配置文件参数值即可:
输出结果:
[WebTest] [INFO] >>> 3
[WebTest] [INFO] >>> 2
[WebTest] [INFO] >>> 0
[WebTest] [INFO] >>> 4
[WebTest] [INFO] >>> 1
===============================================
Factory Test
Total tests run: 5, Failures: 0, Skips: 0
===============================================
可能到这里,还是有同学会说,我的业务数据很复杂,可不是什么123之类,可能就是数据库里查出来的一推业务数据。没问题,接着我们来看看当Factory
和DataProvider
结合在一起,会产生什么效果。
先看一个DataProvider:
public class WebTestDataProvider {
@DataProvider(name = "provider1")
public static Object[][] provider1() {
Object[][] provider = new Object[1][3];
HashMap one = new HashMap () {
{
put("one", "1");
}
};
HashMap two = new HashMap () {
{
put("two", "2");
}
};
return new Object[][] {
{1, "one", one},
{2, "two", two}
};
}
}
这里顺道讲下DataProvider
的使用,分两种:
定义Factory的类中的引用DataProvider
public class WebTestFactory {
@Factory(dataProvider = "provider1", dataProviderClass = com.local.testng.WebTestDataProvider.class)
public Object[] createInstance(Integer index, String name, HashMap content) {
return new Object[] {new FactoryAndProviderTest(index, name, content)};
}
}
这里注意一点
,createInstance的传参需要合DataProvider返回的二维数据的每一行的数据一致,即个数、顺序、类型都要一致,否则testng无法解析。
实际执行的测试类:
public class FactoryAndProviderTest {
private Integer index;
private String name;
private HashMap content;
private static Logger logger = null;
public FactoryAndProviderTest(Integer index, String name, HashMap content) {
this.index = index;
this.name = name;
this.content = content;
}
@BeforeTest
public void setUp() {
logger = Logger.getLogger(FactoryAndProviderTest.class);
}
@Test
public void testServer() {
logger.info("testServer>>> "+this.index);
logger.info("testServer>>> "+this.name);
logger.info("testServer>>> "+this.content.toString());
}
@Test
public void testServer1() {
logger.info("testServer1>>> "+this.index);
logger.info("testServer1>>> "+this.name);
logger.info("testServer1>>> "+this.content.toString());
}
}
suite配置:
运行后,FactoryAndProviderTest中的所有测试类都会循环使用DataProvider中的数据,执行程序的逻辑。
测试结果:
[FactoryAndProviderTest] [INFO] testServer>>> 2
[FactoryAndProviderTest] [INFO] testServer>>> two
[FactoryAndProviderTest] [INFO] testServer>>> {two=2}
[FactoryAndProviderTest] [INFO] testServer>>> 1
[FactoryAndProviderTest] [INFO] testServer>>> one
[FactoryAndProviderTest] [INFO] testServer>>> {one=1}
[FactoryAndProviderTest] [INFO] testServer1>>> 2
[FactoryAndProviderTest] [INFO] testServer1>>> two
[FactoryAndProviderTest] [INFO] testServer1>>> {two=2}
[FactoryAndProviderTest] [INFO] testServer1>>> 1
[FactoryAndProviderTest] [INFO] testServer1>>> one
[FactoryAndProviderTest] [INFO] testServer1>>> {one=1}
===============================================
Factory Test
Total tests run: 4, Failures: 0, Skips: 0
===============================================
讲到这里,大家可能想到当@DataProvider注释某一个TestCase的时候,测试用例也会使用所有数据跑一遍程序逻辑,然后比较下当@Factory和@DataProvider结合,它可以让某个测试类中的所有方法都遍历DataProvider中的数据执行一遍程序逻辑,可以更方便的规划测试用例地执行。