前言:

  说在前边。像我这种假期不出去浪,在这里乖乖写文章研究代码的人,绝壁不是因为爱学习,而是自己不知道去哪玩好,而且也不想玩游戏,看电视剧什么的,结果就无聊到看代码了……

  至于如何解读代码,请把它当做一门语言,况且它就是语言 ,计算机的,那就当做是外国人的语言,可以翻译成汉语的!

  例:system.out.print(" ") 翻译:系统.输出.打印(内容)。如是说!

本文介绍:

  • PropertiesCsvExcelJDBC

初级架构所需代码之 参数配置与读取——properties

  一般代码中需要读取配置有几种方式,在此一一举例说明吧~

  首先,比较常见的是读取properties。一般,我们会将该文件存放在resource当中。

需要了解和使用的几个主要方法:

1.getProperty ( String key),通过参数 key ,得到 key 所对应的 value。

2.load ( InputStream inStream),读取配置,以供 getProperty ( String key) 来搜索。

3.setProperty ( String key, String value) ,set设置,也就是说设置key-value。

4.store ( OutputStream out, String comments),与 load 方法相反,该方法将 key-value 写入到指定的文件中去。

5.clear (),清除所有装载的key-value。该方法在基类中提供。

1和2搭配使用,3和4搭配使用。

实例解说

相比概念性的东西,伸手党以及新手们更喜欢实例的东西来说明。

假如test.properties文件如下:

name=root
pass=admin
key=value

那么读取和使用的方法如下(网上最多的文章是6种properties配置读取方法,我这里推荐使用最常用的是这种):

Properties properties = new Properties();  //调用该方法,不要问为什么
InputStream in =null;  //初始化输入流
in = Obejct.class.getResourceAsStream("/config.properties");  //获取该路径下的properties数据
try {
properties.load(in);  //读取数据
} catch (IOException e) {
e.printStackTrace();
}
properties.getProperty("pass");  //根据key获取values

最后获取的值就是pass对应的admin.(注意你的路径是否正确,以免报错nullPoint)

针对以上的例子,我们看到这样的一句

Obejct.class.getResourceAsStream(path)  //path表示你的properties路径

为了安全起见,更推荐将Obejct改写成你的当前类名,比如 readProperties.class.getResourceAsStream("路径").

参数读取与使用——csv

TestNg中csv数据读取与使用,可以利用此结构遍历csv中的数据,让用例循环执行,直到数据全部读取完毕。

我们新建add.csv到你的任意目录中,比如我的放在这里:

1.直接上代码,首先是csv的数据:

2.创建两个类,一个是基类,用来实现n1+n2=r1这样的功能:

public class Calculator {
public Float add(Float num1,Float num2){
return num1+num2;
}
}

一个是工具类,用来读取csv中的数据:

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;
import java.util.regex.Matcher; public class CsvUtils implements Iterator<Object[]> {
BufferedReader in;
ArrayList<String> csvList=new ArrayList<String>();
int rowNum=0; //行数
int columnNum=0; //列数
int curRowNo=0; //当前行数
String columnName[]; //列名
/**
* 在TestNG中由@DataProvider(dataProvider = "name")修饰的方法取csv数据时,
* 调用此类构造方法(此方法会得到列名),
* 返回给由@Test(dataProvider = "name")修饰的方法,如此
* 反复到数据读完为止
* @param fileName 文件名
* @throws IOException
*/
public CsvUtils(String fileName) throws IOException{
File directory=new File(".");
String path=".src.main.java.page.testdata."; //文件路径
String absolutePath=directory.getCanonicalPath()+path.replaceAll("\\.", Matcher.quoteReplacement("\\"))+fileName;
System.out.println(absolutePath); //打印路径
File csv=new File(absolutePath);
in=new BufferedReader(new FileReader(csv)); //读取csv数据
while (in.ready()) {
csvList.add(in.readLine());
this.rowNum++;
}
String[] str=csvList.get(0).split(",");
this.columnNum=str.length;
columnName=new String[columnNum];
//获取列名
for (int i = 0; i < columnNum; i++) {
columnName[i]=str[i];
}
this.curRowNo++;
}
@Override
public boolean hasNext() {
// TODO Auto-generated method stub
if(rowNum==0||curRowNo>=rowNum){
try {
in.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return false;
}else{
return true;
}
}
/**
* 获取一组参数,即一行数据
*/
@Override
public Object[] next() {
// TODO Auto-generated method stub
Map<String,String> s=new TreeMap<String,String>();
String csvCell[]=csvList.get(curRowNo).split(",");
for(int i=0;i<this.columnNum;i++){
s.put(columnName[i], csvCell[i]);
}
Object[] d=new Object[1];
d[0]=s;
this.curRowNo++;
return d;
} @Override
public void remove() {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("remove unsupported");
} }

CSVUtils

3.实现类

import java.io.IOException;
import java.util.Iterator;
import java.util.Map; import core.utils.CsvUtils;
import org.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test; public class CsvTest{
Calculator cal=new Calculator(); @DataProvider(name="num")
public Iterator<Object[]> Numbers() throws IOException{
return (Iterator<Object[]>)new CsvUtils("add.csv");
}
@Test(dataProvider="num")
public void testAdd(Map<String, String> data){
float num1=Float.parseFloat(data.get("n1"));
float num2=Float.parseFloat(data.get("n2"));
float expectedResult=Float.parseFloat(data.get("r1"));
Float actual=cal.add(num1, num2);
Assert.assertEquals(actual, expectedResult);
}
}

4.执行结果:

不要光看,自己敲一遍就知道什么意思了!

Excel数据的读取

对于已经写好了脚本的同学,多数采用的是这种数驱的形式,这种形式很方便维护自己的用例,完全不用打开编译器,改改数据就好。

但是,它也同样存在弊端,比如数据量相对大起来的时候,比如需要网络调用的时候,我们都没有很好的办法去维护它,不过我们同样要掌握这种数据读取和使用的方法。

针对于Excel还有个要考虑的问题,那就是版本的问题,因为excel分为97-03,07+版,也就是文件后缀是.xls.xlsx的两种版本(官网为什么不把14年前的版本干掉……要统一啊~),

所以,我们还要针对这两种情况来整合封装一个类,来实现根据后缀名判断调用方法。

可以实现该功能的包有两个:poijxl,至于优势和劣势自己网上搜吧。

1.这里先介绍下POI的一些用法,首先它更适用于97-2008版本的Excel(Apache-POI官网);

可能会用到的字段说明:

  • HSSF - 提供读写Microsoft Excel XLS格式档案的功能。
  • XSSF - 提供读写Microsoft Excel OOXML XLSX格式档案的功能。
  • HWPF - 提供读写Microsoft Word DOC格式档案的功能。
  • HSLF - 提供读写Microsoft PowerPoint格式档案的功能。
  • HDGF - 提供读Microsoft Visio格式档案的功能。
  • HPBF - 提供读Microsoft Publisher格式档案的功能。
  • HSMF - 提供读Microsoft Outlook格式档案的功能。

关于Maven引用:

<!-- poi-ooxml同时支持XLS和XLSX两种格式 -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.17</version>
</dependency>

思路:

创建读取Excel-xlsx格式的类;

/**
* 读取2007-2013格式
* @param filePath 文件路径
* @return excel以数组形式返回
* @throws java.io.IOException
*/
@SuppressWarnings("rawtypes")
public static List<Map> readXLSX(String filePath) throws IOException {
List<Map> valueList = new ArrayList<Map>();
FileInputStream fis = null;
try {
fis = new FileInputStream(filePath);
XSSFWorkbook xwb = new XSSFWorkbook(fis); // 构造 XSSFWorkbook 对象,strPath 传入文件路径
XSSFSheet sheet = xwb.getSheetAt(0); // 读取第一章表格内容
// 定义 row、cell
XSSFRow row;
// 循环输出表格中的第一行内容 表头
Map<Integer, String> keys = new HashMap<Integer, String>();
row = sheet.getRow(0);
if (row != null) {
//System.out.println("j = row.getFirstCellNum()::"+row.getFirstCellNum());
//System.out.println("row.getPhysicalNumberOfCells()::"+row.getPhysicalNumberOfCells());
for (int j = row.getFirstCellNum(); j <= row.getPhysicalNumberOfCells(); j++) {
// 通过 row.getCell(j).toString() 获取单元格内容,
if (row.getCell(j) != null) {
if (!row.getCell(j).toString().isEmpty()) {
keys.put(j, row.getCell(j).toString());
}
} else {
keys.put(j, "K-R1C" + j + "E");
}
}
}
// 循环输出表格中的从第二行开始内容
for (int i = sheet.getFirstRowNum() + 1; i <= sheet.getPhysicalNumberOfRows(); i++) {
row = sheet.getRow(i);
if (row != null) {
boolean isValidRow = false;
Map<String, Object> val = new HashMap<String, Object>();
for (int j = row.getFirstCellNum(); j <= row.getPhysicalNumberOfCells(); j++) {
XSSFCell cell = row.getCell(j);
if (cell != null) {
String cellValue = null;
if (cell.getCellType() == XSSFCell.CELL_TYPE_NUMERIC) {
if (DateUtil.isCellDateFormatted(cell)) {
cellValue = new DataFormatter().formatRawCellContents(cell.getNumericCellValue(), 0, "yyyy-MM-dd HH:mm:ss");
} else {
cellValue = String.valueOf(cell.getNumericCellValue());
}
} else {
cellValue = cell.toString();
}
if (cellValue != null && cellValue.trim().length() <= 0) {
cellValue = null;
}
val.put(keys.get(j), cellValue);
if (!isValidRow && cellValue != null && cellValue.trim().length() > 0) {
isValidRow = true;
}
}
} // 第I行所有的列数据读取完毕,放入valuelist
if (isValidRow) {
valueList.add(val);
}
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
fis.close();
}
return valueList;
}

readXLSX

创建读取Excel-xls格式的类;

 /**
* 读取97-2003格式
* @param filePath 文件路径
* @throws java.io.IOException
*/
@SuppressWarnings("rawtypes")
public static List<Map> readXLS(String filePath) throws IOException{
//返回结果集
List<Map> valueList=new ArrayList<Map>();
FileInputStream fis=null;
try {
fis=new FileInputStream(filePath);
HSSFWorkbook wookbook = new HSSFWorkbook(fis); // 创建对Excel工作簿文件的引用
HSSFSheet sheet = wookbook.getSheetAt(0); // 在Excel文档中,第一张工作表的缺省索引是0
int rows = sheet.getPhysicalNumberOfRows(); // 获取到Excel文件中的所有行数­
Map<Integer,String> keys=new HashMap<Integer, String>();
int cells=0;
// 遍历行­(第1行 表头) 作为Map里的key
HSSFRow firstRow = sheet.getRow(0);
if (firstRow != null) {
// 获取到Excel文件中的所有的列
cells = firstRow.getPhysicalNumberOfCells();
// 遍历列
for (int j = 0; j < cells; j++) {
// 获取到列的值­
try {
HSSFCell cell = firstRow.getCell(j);
String cellValue = getCellValue(cell);
keys.put(j,cellValue);
} catch (Exception e) {
e.printStackTrace();
}
}
}
// 遍历行­(从第二行开始)
for (int i = 1; i < rows; i++) {
// 读取左上端单元格(从第二行开始)
HSSFRow row = sheet.getRow(i);
// 行不为空
if (row != null) {
//准备当前行 所储存值的map
Map<String, Object> val=new HashMap<String, Object>(); boolean isValidRow = false; // 遍历列
for (int j = 0; j < cells; j++) {
// 获取到列的值­
try {
HSSFCell cell = row.getCell(j);
String cellValue = getCellValue(cell);
val.put(keys.get(j),cellValue);
if(!isValidRow && cellValue!=null && cellValue.trim().length()>0){
isValidRow = true;
}
} catch (Exception e) {
e.printStackTrace();
}
}
//第I行所有的列数据读取完毕,放入valuelist
if(isValidRow){
valueList.add(val);
}
}
}
} catch (IOException e) {
e.printStackTrace();
}finally {
fis.close();
}
return valueList;
} /**
* 返回表内正确的内字符类型
* @param cell 表格
* @return
*/
private static String getCellValue(HSSFCell cell) {
DecimalFormat df = new DecimalFormat("#");
String cellValue=null;
if (cell == null)
return null;
switch (cell.getCellType()) {
case HSSFCell.CELL_TYPE_NUMERIC:
if(HSSFDateUtil.isCellDateFormatted(cell)){
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
cellValue=sdf.format(HSSFDateUtil.getJavaDate(cell.getNumericCellValue()));
break;
}
cellValue=df.format(cell.getNumericCellValue());
break;
case HSSFCell.CELL_TYPE_STRING:
cellValue=String.valueOf(cell.getStringCellValue());
break;
case HSSFCell.CELL_TYPE_FORMULA:
cellValue=String.valueOf(cell.getCellFormula());
break;
case HSSFCell.CELL_TYPE_BLANK:
cellValue=null;
break;
case HSSFCell.CELL_TYPE_BOOLEAN:
cellValue=String.valueOf(cell.getBooleanCellValue());
break;
case HSSFCell.CELL_TYPE_ERROR:
cellValue=String.valueOf(cell.getErrorCellValue());
break;
}
if(cellValue!=null&&cellValue.trim().length()<=0){
cellValue=null;
}
return cellValue;
}

readXLS

根据文件名选择执行对应的类;

/**
* 根据文件名自动识别读取方式
* 同时支持xls及xlsx格式的Excel数据读取
*
* @param filepath 文件名:包含路径及扩展名
* @return 返回列表内容格式:
* 每一行数据都是以对应列的表头为key 内容为value 比如 excel表格为:
* ===============
* A | B | C | D
* ===|===|===|===
* 1 | 2 | 3 | 4
* ---|---|---|---
* a | b | c | d
* ---------------
* 返回 [{A=1, B=2, C=3, D=4}, {A=a, B=b, C=c, D=d}]
* @throws java.io.IOException
*/
public static List<Map> readExcel(String filepath) {
List<Map> valueList = new ArrayList<Map>(); try {
if (new FileUtils().getuffix(filepath).equalsIgnoreCase("xlsx")) {
valueList = ExcelUtils.readXLSX(filepath);
}
if (new FileUtils().getuffix(filepath).equalsIgnoreCase("xls")) {
valueList = ExcelUtils.readXLS(filepath);
} else {
throw new ErrorOnSettingException("此文件不是Excel文件");
}
} catch (Exception e) {
e.printStackTrace();
}
return valueList;
}

readExcel

文件名工具类;

public class FileUtils {
/**
* 获取文件名
*
* @param fileName 文件名包含扩展名
* @return 返回获取的文件名
*/
public String getFileName(String fileName) {
fileName = fileName.trim();
String fName = fileName.substring(fileName.lastIndexOf("/") + 1);
return fName;
}
}

FileUtils

实现类:

ExcelUtils.readExcel(filepath);

 JDBC数据的读取

本文最后要介绍JDBC的数据读取,如何使用数据库的数据到你的脚本中使用,也是数据参数驱动的一种常用方式;

针对数据量相对大的场景,首推数据库来保存你的参数,也更方便维护;

相对于其他方式,jdbc在使用结束后,一定要关闭输入流,就像webdriver使用结束后要有个webdriver.close()是一样的,下边的代码中你也可以看到。

假如数据库中的数据如下:

数据库配置与链接:

        // 数据库类型
private static String DBTYPE = "mysql";
// 数据库地址 格式:jdbc:mysql://ip:port/tablename?参数(可有可无,根据需要添加参数)
private static String DB_URL = "jdbc:mysql://localhost:3306/antmember_test?characterEncoding=utf8&useSSL=true&serverTimezone=UTC";
// 数据库登录账号
private static String USERNAME = "";
// 数据库登录密码
private static String PASSWORD = "";
// 数据库表名
private static String TABLENAME = "";
// 链接数据库
private static Connection conn = null;
// 向数据库发送sql语句
private static Statement statement = null;
// 返回sql执行结果
private static ResultSet resultSet = null; /**
* 根据config配置信息,链接对应的数据库
*/
public static void dbConnect () { System.out.println("读取数据库配置并开始链接");
try {
if (DBTYPE.equals("mysql")) {
Class.forName("com.mysql.cj.jdbc.Driver");
}
if (DBTYPE.equals("oracle")) {
Class.forName("oracle.jdbc.driver.OracleDriver");
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} }

配置与链接

数据库的查询:

        public static void dbSelect (String sql, String detail){
dbConnect();
try {
//登录数据库
conn = DriverManager.getConnection(DB_URL, USERNAME, PASSWORD);
//创建并执行sql语句
statement = conn.prepareStatement(sql);
//返回sql执行结果
resultSet = statement.executeQuery(sql); JsonObject object = new JsonObject();
JsonArray array = new JsonArray(); while (resultSet.next()) {
JsonObject ob = new JsonObject();
ob.addProperty(detail, resultSet.getString(detail));
array.add(ob);
}
object.add("查询结果:", array);
System.out.println(object.toString());
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
} }

查询

为了方便查看返回结果,我还用了json解析格式输出到控制台中,同样,你也可以输出到你的文档中,或者日志当中(json解析需要引入gson这个jar包,maven的方法我就不说了),另外,关于其他数据库的链接方式如下:

# 连接MySql数据库:Connection conn = DriverManager.getConnection("jdbc:mysql://host:port/database", "user", "password");
# 连接Oracle数据库:Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@host:port:database", "user", "password");
# 连接SqlServer数据库:Connection conn = DriverManager.getConnection("jdbc:microsoft:sqlserver://host:port; DatabaseName=database", "user", "password");
# 其他参数如:useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=UTC

使用:

    //我的表名:sm_user_info
    String sql = "SELECT * FROM sm_user_info WHERE id_type = 'git'";
dbSelect(sql, "user_id");

控制台上的执行结果:

至此,本文介绍完毕。

当然还有很多可以讲的东西,大家不妨如此这般的各种尝试一下吧。

有问题可以留言下方,我会及时解答,并补充说明

关于自动化测试框架,所需代码技能,Java篇——参数配置与读取.的更多相关文章

  1. 基于Python接口自动化测试框架+数据与代码分离(进阶篇)附源码

    引言 在上一篇<基于Python接口自动化测试框架(初级篇)附源码>讲过了接口自动化测试框架的搭建,最核心的模块功能就是测试数据库初始化,再来看看之前的框架结构: 可以看出testcase ...

  2. Java自动化测试框架-03 - TestNG之Test Group篇 - 我们一起组团打怪升级(详细教程)

    简介 其实这篇文章的group宏哥在上一篇中就提到过,但是就是举例一笔带过的,因此今天专门有一篇文章来讲解Group的相关知识.希望大家茅塞顿开 ,有着更进一步认识和了解测试组. 一.Test Gro ...

  3. Java自动化测试框架-04 - TestNG之Test Method篇 - 道法自然,法力无边(详细教程)

    简介 按照上一篇的计划,这一篇给小伙伴们分享一下测试方法. 一.设置参数 测试方法是可以带有参数的.每个测试方法都可以带有任意数量的参数,并且可以通过使用TestNG的@Parameters向方法传递 ...

  4. Robot Framework自动化测试框架核心指南-如何使用Java编写自定义的RobotFramework Lib

    如何使用Java编写自定义的RobotFramework Lib 本文包括2个章节 1. Robot Frdamwork中如何调用java Lib库 2.使用 java编写自定义的Lib 本文作者为: ...

  5. Java自动化测试框架-09 - TestNG之依赖注入篇 (详细教程)

    1.-依赖注入 TestNG支持两种不同类型的依赖项注入:本机(由TestNG本身执行)和外部(由诸如Guice的依赖项注入框架执行). 1.1-本机依赖项注入 TestNG允许您在方法中声明其他参数 ...

  6. Appium+python自动化(三十九)-Appium自动化测试框架综合实践 - 代码实现(超详解)

    简介 经过一段时间的准备,完善的差不多了,继续分享有关Appium自动化测试框架综合实践.想必小伙伴们有点等不及了吧! driver配置封装 kyb_caps.yaml 配置表 参考代码 platfo ...

  7. Appium+python自动化(四十)-Appium自动化测试框架综合实践 - 代码实现(超详解)

    1.简介 今天我们紧接着上一篇继续分享Appium自动化测试框架综合实践 - 代码实现.由于时间的关系,宏哥这里用代码给小伙伴演示两个模块:注册和登录. 2.业务模块封装 因为现在各种APP的层出不群 ...

  8. 管中窥豹——框架下的SQL注入 Java篇

    管中窥豹--框架下的SQL注入 Java篇 背景 SQL注入漏洞应该算是很有年代感的漏洞了,但是现在依然活跃在各大漏洞榜单中,究其原因还是数据和代码的问题. SQL 语句在DBMS系统中作为表达式被解 ...

  9. 查看Java JVM参数配置信息命令

    查看Java JVM参数配置信息命令 java -XX:+PrintCommandLineFlags jvm运行时状态的参数,可以很快找出问题所在.现在把几个命令记录一下:1. jstat这个命令对于 ...

随机推荐

  1. Centos7下Mysql通过.frm和.ibd恢复数据

    通过.frm和.ibd文件恢复表结构和数据 这里以hue数据库中的desktop_document2表为例 分成两步骤,先去表结构,再取数据,最好在一个用完就可以删除的数据库中进行 取表结构篇: 1. ...

  2. 如何查找论文是否被SCI,EI检索(转)

      转自 http://blog.sina.com.cn/s/blog_564978430100iqpp.html   学术界,尤其是国内学术界,把SCI,EI看得太重,很多大学都要求博士毕业要有SC ...

  3. November 16th 2016 Week 47th Wednesday

    Success is falling nine times and getting up ten. 成功就是哪怕跌倒九次,也要在第十次爬起来. For most of us, we may choos ...

  4. APUE 4.8 umask函数

  5. ubuntu 12.04 64位 安装wps

    1.去wps官网下载linux版的软件 http://community.wps.cn/download/ 我这里下载的是Alpha版的kingsoft-office_9.1.0.4280~a12p4 ...

  6. rabbitmq的万能安装和外网访问(NC版)

    先去这个http://www.rabbitmq.com/releases/下载erlang环境和rpm(erlang的尽量高点,rabbitmq版本差不多就可以了,) erlang-19.0.4-1. ...

  7. Java认证与授权服务JAAS基础概念

    转:http://www.nosqlnotes.com/technotes/jaas-concept/ JAAS是”Java Authentication and Authorization Serv ...

  8. php魔术变量

    __LINE__   文件中的当前行号 __FILE__ 文件的完整路径和文件名 __DIR__  文件所在的目录 __FUNCTION__  自 PHP 5 起本常量返回该函数被定义时的名字 __C ...

  9. C 六学家的困惑 【YY】 (2019年华南理工大学程序设计竞赛(春季赛))

    冲鸭,去刷题:https://ac.nowcoder.com/acm/contest/625/C 小六喜欢两全其美的事情,今天就正好有一个这样的机会. 小六面前有两根管子,管子里面放满了数字为1到9的 ...

  10. [luogu3943] 星空

    题面 ​ 这个题目大意上是这样的:给定一个长度为n的01串, 其中只有k个0, 每次操作时, 从给定的m种长度中选择一种, 选择序列上长度为这种的进行反转操作, 求至少需要多少次操作使得整个串全变为1 ...