一:testng参数化
常见的参数化方式,有2种。
1:配合testng.xml,使用parameters
#testng.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="All Test Suite">
<test verbose="2" preserve-order="true" name="test1">
<classes>
<class name="com.mhc.tester.VipSettlementTest">
<parameter name="password" value="password0"></parameter>
<parameter name="username" value="name0"></parameter>
</class>
</classes>
</test>
</suite>
对应的VipSettlementTest类中,就可以直接使用@parameters注解,引入xml中设置的参数。注意参数名和xml中设置的参数名要求一致。
//利用testng.xml,完成简单的参数化
@Parameters({"username","password"})
@Test(testName = "test1")
public void printParameter(String name,String psd){
System.out.println(name+psd);
}
本身的项目结构如下。
由于一开始项目中无testng.xml文件,那么可以在plugins中下一个"create testng xml"插件,这样可以右键生成项目的testng.xml。避免格式错误。
说一下这里处理过程中遇到的坑
1:单独运行Java文件中的测试类,直接报错。
上网搜索答案,说是单独运行这个类时,并没用运行testng.xml,没有获取到注解中参数对应的值。所以报错。
解决方式为:不要单独运行对应的测试类,单独运行testng.xml。它会执行xml中包含的所有用例
2:一开始自己编写testng.xml。直接在suit下面设置了一个test,然后直接就放了paramter,导致参数没有找到测试类去运行。在test下面加上了要执行的类才解决这个问题。
2:dataprovider构造参数
构造参数的方法编写
//这个样例比较复杂,是构造类一个接口调用需要用到的自定义form。数据构造函数的返回是一维object数组
@DataProvider(name="wmsPreSettlementFeeForm")
@Test
public Object[] createWmsPreSettlementFeeForm() throws SQLException, ClassNotFoundException {
List<Long> wmsCarIdLists = new ArrayList<>();
List<Object[]> result = new ArrayList<>();
Long list = 197181L;
wmsCarIdLists.add(list);
Object []objects = new Object[1];
QueryWmsCarSettlementForm form = new QueryWmsCarSettlementForm();
MysqlConn conn = new MysqlConn(B2B.getDriver(),B2B.getUrl(),B2B.getName(),B2B.getPassword());
conn.getConnection();
System.out.println("this is connection established");
System.out.println(wmsCarIdLists);
wmsCarIdLists.forEach(wmsCarIdList->{
System.out.println(wmsCarIdList);
String sql = "select asset_right,cc_car_id from wms_car left join cc_car on wms_car.cc_car_id = cc_car.car_id where `wms_car_id` ="+wmsCarIdList+";";
System.out.println(sql+"the sql sequence is ");
List<Long> ccCarIdList = new ArrayList<>();
try {
ResultSet resultSet = conn.queryX(sql);
resultSet.next();
form.setOwnerId(resultSet.getLong("asset_right"));
form.setOwnerType(2);
ccCarIdList.add(resultSet.getLong("cc_car_id"));
form.setFromType(1);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
form.setCcCarIdList(ccCarIdList);
form.setWmsCarIdList(wmsCarIdLists);
Date date = new Date();
SimpleDateFormat simpleDateFormat =new SimpleDateFormat("yyyy-MM-dd");
form.setPreSettleDate(simpleDateFormat.format(date));
});
objects[0]=form;
result.add(objects);
conn.closeX();
System.out.println(result);
return objects;
}
测试函数,需要调用参数构造函数的返回值的编写方式。
@Test(dataProvider="wmsPreSettlementFeeForm")
public void getWmsPreSettlementFeeTest(QueryWmsCarSettlementForm form) throws SQLException, ClassNotFoundException {
String finalFee="";
System.out.println("form is "+form);
DubboResult<CarReceivableFeeSettlementDTO> carReceivableFeeSettlementDTO = wmsCarSettlementService.getWmsPreSettlementFee(form);
if(carReceivableFeeSettlementDTO != null){
finalFee = carReceivableFeeSettlementDTO.getData().getFinalFee();
System.out.println("actual_fee is "+finalFee);
System.out.println("there is data\n\t"+carReceivableFeeSettlementDTO.getData());}
//获取数据库对应的值
MysqlConn conn = new MysqlConn(B2B.getDriver(),B2B.getUrl(),B2B.getName(),B2B.getPassword());
conn.getConnection();
String wms_car_id = form.getWmsCarIdList().get(0).toString();
System.out.println("wms_car_id is"+wms_car_id);
String sqlExcept = "select sum(`final_fee`) as total_fee from `wms_car_receivable_daily_fee` where `wms_car_id`="+ wms_car_id +" and `status`=1 and `settle_status`=0";
ResultSet resultSet = conn.queryX(sqlExcept);
resultSet.next();
String except = resultSet.getString("total_fee");
FormatController formatController = new FormatController();
except=formatController.stringTwoDemicalString(except);
conn.closeX();
System.out.println("there is except fee"+except);
Assert.assertEquals(finalFee,except,"there has error,final_fee not the same");
}
踩过的坑
1:dataprovider函数的返回值
这个函数只支持4种返回结果。
知道参数个数的:object[],object[][], 顾名思义分别是一个由广义对象组成的1维数组和一个二维数组。而二维数组种每一行为执行一次测试用例使用的参数,列数为循环执行的次数。
不知道参数个数的:Iterator 和Iterator<Object[]>。可以通过add方法,增加测试用例组数。
2:测试执行函数,传递的参数格式为 dataprovider中每组测试用例的数据格式,而非 object[]之类的。
3:编写习惯问题。定义对象列表,一定要编写清楚,知名对象类型,如List ccCarIdList = new ArrayList<>();这样在后续赋值传参能保证格式正确行,今天就是在这里直接写了 list ccCarIdList = new ArrayList<>(),把long格式的字符串用string格式传参,出现了反序列化出错,导致拉着别人看了一半天的dubbo版本一致性问题……
3:小结
@parameters:适合用于参数比较少,比较简单的情况下,直接xml赋值注入了。当然,xml里面的value,也可以链接到文件名,然后调用函数打开文件获取信息。
@dataprovider:适合用于参数比较复杂的情况,那么需要手动创建。
在测试函数使用了dataprovider的情况,测试必须要有形参,这样才能和dataprovider的返回参数获取信息。
4:遗留问题
测试类继承AbstractTestNGSpringContextTests后,在类里面定义一个测试方法,将方法加上@Test注解就可以被testng执行。但是,当我的测试方法返回值不为0时,或者有形参需要传入(未调用dataprovider的情况下),添加了test注解,还是没用被testng执行,找不到对应的测试方法。这个还未理解为什么。