综述,本次做一个查询接口 的自动化测试案例,采用excel管理测试用例,ExtendReport呈现报告(前面有简单demo),Log4j记录日志(前面有简单demo),testng搭建测试框架。其中接口请求格式如下:
接口有数据时,返回如下:
其中Table格式如下:
1.新建Maven项目,引入操作Excel的jar包:
org.apache.poi
poi
3.10-FINAL
org.apache.poi
poi-ooxml
3.9
2.新建Excel工具类,ExcelUtil,代码如下:
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
public class ExcelUtil {
private static XSSFSheet ExcelWSheet;
private static XSSFWorkbook ExcelWBook;
private static XSSFCell cell;
private static XSSFRow row;
//设定要读写的Excel文件路径和文件名
public static void setExcelFile(String path, String sheetName) throws Exception{
FileInputStream excelFile = new FileInputStream(path);
ExcelWBook = new XSSFWorkbook(excelFile);
ExcelWSheet = ExcelWBook.getSheet(sheetName);
}
//读取Excel文件指定单元格,此函数只支持.xlsx的文件
public static String getCellData(int rowNum, int colNum){
System.out.println("1");
//cell = ExcelWSheet.getRow(rowNum).getCell(colNum);
row = ExcelWSheet.getRow(rowNum);
if(!row.equals(null)) cell = row.getCell(colNum);
System.out.println("2");
String cellData = (String)(cell.getCellType() == XSSFCell.CELL_TYPE_STRING ? cell.getRichStringCellValue()+"": cell.getNumericCellValue());
System.out.println("3");
return cellData;
}
//在Excel文件的指定单元格写入数据,只能支持.xlsx的文件
public static void setCellData(int rowNum, int colNum,String result,String filePath) throws Exception{
row =ExcelWSheet.getRow(rowNum);
cell = row.getCell(colNum,Row.RETURN_BLANK_AS_NULL);
if(cell == null){
cell = row.createCell(colNum);
cell.setCellValue(result);
}else{
cell.setCellValue(result);
}
FileOutputStream fileOut = new FileOutputStream(filePath);
ExcelWBook.write(fileOut);
fileOut.flush();
fileOut.close();
}
//从Excel文件获取测试数据的静态方法,返回二维数组对象
public static Object[][] getTestData(String excelFilePath, String sheetName) throws IOException{
File file = new File(excelFilePath);
FileInputStream inputStream = new FileInputStream(file);
Workbook Workbook = null;
//获取文件名的扩展名
String fileExtensionName = excelFilePath.substring(excelFilePath.indexOf("."));
//.xlsx时实例化XSSFWorkbook对象;xls时实例化HSSFWorkbook
if(fileExtensionName.equals(".xlsx")){
Workbook = new XSSFWorkbook(inputStream);
}else if(fileExtensionName.equals(".xls")){
Workbook = new HSSFWorkbook(inputStream);
}
//生成sheet对象
Sheet Sheet = Workbook.getSheet(sheetName);
//获取sheet表的行数,行号和列号都是从0开始的
int rowCount = Sheet.getLastRowNum() - Sheet.getFirstRowNum();
// System.out.println("行数:"+rowCount+"最后一行行号:"+Sheet.getLastRowNum()+"第一行行号:"+Sheet.getFirstRowNum());
//用来存放读取的数据,list对象
List
在某路径下新建excel文件,建议为.xlsx的,文档内容如下(根据自己所要测试的接口调整):
3.新建两个对象类,一个是用来管理请求参数,一个用来管理接口返回的json数据(自己根据所测试接口添加),代码如下:
请求类:
public class I_kuaQuMenZhen {
private Object sin;
private Object servicecode;
private Object authoucode;
private Object action;
public I_kuaQuMenZhen(){}
public void setSin(Object sin){
this.sin = sin;
}
public void setservicecode(Object servicecode){
this.servicecode = servicecode;
}
public void setauthoucode(Object data){
this.authoucode = data;
}
public void setaction(Object action){
this.action = action;
}
public Object getSin(){
return this.sin;
}
public Object getservicecode(){
return this.servicecode;
}
public Object getauthoucode(){
return this.authoucode;
}
public Object getaction(){
return this.action;
}
public void getString(){
System.out.println("sin:"+this.sin+"servicecode:"+this.servicecode+"authoucode:"+this.authoucode+"aciton:"+this.action);
}
}
接口返回类:
public class I_kuaQuMenZhenJiekouReturn {
private Object AuthOUCode;
private Object AuthOUName;
private Object ExpiryDate;
private Object InDate;
private Object ServiceCode;
private Object ServiceName;
public void setAuthOUCode(Object AuthOUCode){
this.AuthOUCode = AuthOUCode;
}
public void setAuthOUName(Object AuthOUName){
this.AuthOUName = AuthOUName;
}
public void setExpiryDate(Object ExpiryDate){
this.ExpiryDate = ExpiryDate;
}
public void setInDate(Object InDate){
this.InDate = InDate;
}
public void setServiceCode(Object ServiceCode){
this.InDate = ServiceCode;
}
public void setServiceName(Object ServiceName){
this.ServiceName = ServiceName;
}
public Object getAuthOUCode(){
return this.AuthOUCode;
}
public Object getAuthOUName(){
return this.AuthOUName;
}
public Object getExpiryDate(){
return this.ExpiryDate;
}
public Object getInDate(){
return this.InDate;
}
public Object getServiceCode(){
return this.ServiceCode;
}
public Object getServiceName(){
return this.ServiceName;
}
public String toString(){
return "";
}
}
4.引入extendReport、Log4j、testng所需要的jar包,并新建extendReport的监听器类,Log4j的工具类及配置文件,步骤请参考前两章。
5.引入httpClient的jar包
org.apache.httpcomponents
httpclient
4.5.6
由于接口请求和返回参数都是json格式,需要引入以下jar包:
net.sf.json-lib
json-lib
2.4
jdk15
com.alibaba
fastjson
1.2.4
新建接口请求类,调用httpClient实现
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import com.alibaba.fastjson.JSONObject;
import duixiang.I_kuaQuMenZhen;
import uitl.ExcelUtil;
import uitl.Log;
/**
*
* @author liususu
* @category 跨区门诊查询接口
*
*/
public class KuaQuMZ {
private HttpPost post;
private CloseableHttpClient httpClient;
private JSONObject json;
//直接指定excel行执行请求
public JSONObject send_I_kuaQ(String path,String sheetName,int rowNum) throws Exception{
try{
String JsonReturn = new String();
Log.info("开始读取Excel数据");
I_kuaQuMenZhen sendParm = getParm(path, sheetName, rowNum);
JSONObject bodyJsonParam = new JSONObject();
bodyJsonParam.put("sin",sendParm.getSin());
bodyJsonParam.put("servicecode",sendParm.getservicecode());
bodyJsonParam.put("authoucode",sendParm.getservicecode());
JSONObject headJsonParam = new JSONObject();
headJsonParam.put("action",sendParm.getaction());
JSONObject allJsonParam = new JSONObject();
allJsonParam.put("body",bodyJsonParam);
allJsonParam.put("head", headJsonParam);
//创建请求对象
post = new HttpPost("请求地址");
httpClient = HttpClients.createDefault();
//4.创建请求体
//StringEntity---UrlEncodedFormEntity
//参考地址https://blog.csdn.net/tb_520/article/details/80447794
StringEntity entity = new StringEntity(allJsonParam.toString(),"utf-8");
entity.setContentEncoding("UTF-8");
entity.setContentType("application/json");
Log.info("请求参数:"+allJsonParam.toString());
//5.设置请求参数
post.setEntity(entity);
//6.开始执行请求
Log.startTestCase("跨区门诊查询接口开始请求");
HttpResponse response = httpClient.execute(post);
// 7.保存接口返回的响应码
int statusCode = response.getStatusLine().getStatusCode();
if(statusCode != HttpStatus.SC_OK){
Log.error("请求错误码为: "+statusCode);
json = null;
}else{
Log.info("请求正确响应码为: "+statusCode);
//7.得到接口返回的响应体
HttpEntity RespEntity = response.getEntity();
if (RespEntity != null) {
JsonReturn = EntityUtils.toString(RespEntity, "UTF-8");
Log.info("--------------------------------------");
Log.info("Response content: " + JsonReturn);
json = JSONObject.parseObject(JsonReturn);
Log.info("--------------------------------------");
Log.endTestCase("跨区门诊查询接口结束");
}
}
} catch (Exception e) {
e.printStackTrace();
}finally{
if(post != null){
try {
post.releaseConnection();
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
return json;
}
//使用dataprovider提供测试数据
public JSONObject send_I_kuaQDataPro(Object[] parm) throws Exception{
try{
String JsonReturn = new String();
Log.info("开始读取Excel数据");
I_kuaQuMenZhen sendParm = getParmDataPro(parm);
JSONObject bodyJsonParam = new JSONObject();
bodyJsonParam.put("sin",sendParm.getSin());
bodyJsonParam.put("servicecode",sendParm.getservicecode());
bodyJsonParam.put("authoucode",sendParm.getservicecode());
JSONObject headJsonParam = new JSONObject();
headJsonParam.put("action",sendParm.getaction());
JSONObject allJsonParam = new JSONObject();
allJsonParam.put("body",bodyJsonParam);
allJsonParam.put("head", headJsonParam);
//创建请求对象
post = new HttpPost("请求地址");
httpClient = HttpClients.createDefault();
//4.创建请求体
//StringEntity---UrlEncodedFormEntity
//参考地址https://blog.csdn.net/tb_520/article/details/80447794
StringEntity entity = new StringEntity(allJsonParam.toString(),"utf-8");
entity.setContentEncoding("UTF-8");
entity.setContentType("application/json");
// Log.info("请求参数:"+allJsonParam.toString());
//5.设置请求参数
post.setEntity(entity);
//6.开始执行请求
Log.startTestCase("跨区门诊查询接口开始请求");
HttpResponse response = httpClient.execute(post);
// 7.保存接口返回的响应码
int statusCode = response.getStatusLine().getStatusCode();
if(statusCode != HttpStatus.SC_OK){
Log.error("请求错误码为: "+statusCode);
json = null;
}else{
Log.info("请求正确响应码为: "+statusCode);
//7.得到接口返回的响应体
HttpEntity RespEntity = response.getEntity();
if (RespEntity != null) {
JsonReturn = EntityUtils.toString(RespEntity, "UTF-8");
//Log.info("--------------------------------------");
//Log.info("Response content: " + JsonReturn);
json = JSONObject.parseObject(JsonReturn);
//Log.info("--------------------------------------");
Log.endTestCase("跨区门诊查询接口结束");
}
}
} catch (Exception e) {
e.printStackTrace();
}finally{
if(post != null){
try {
post.releaseConnection();
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
return json;
}
public I_kuaQuMenZhen getParm(String path,String sheetName,int rowNum) throws Exception{
Object[][] data = ExcelUtil.getTestData(path, sheetName);
I_kuaQuMenZhen demo1 = new I_kuaQuMenZhen();
demo1.setSin(data[rowNum-2][1]);
demo1.setservicecode(data[rowNum-2][2]);
demo1.setauthoucode(data[rowNum-2][3]);
demo1.setaction(data[rowNum-2][4]);
// demo1.getString();
return demo1;
}
public I_kuaQuMenZhen getParmDataPro(Object[] dataP) throws Exception{
I_kuaQuMenZhen demo1 = new I_kuaQuMenZhen();
demo1.setSin(dataP[1]);
demo1.setservicecode(dataP[2]);
demo1.setauthoucode(dataP[3]);
demo1.setaction(dataP[4]);
return demo1;
}
}
6.新建测试类,两种方式,一种是直接指定单元格读取数据,将每行数据写一个@Test方法,第二种使用@DataProvider和@Test实现。注意:excel数据表格的路径,请修改为自己的存放路径。
首先第一种,每行测试用例为一个测试方法,这种方式在报告中可以呈现自己写的测试备注。
import org.testng.Assert;
import org.testng.annotations.Test;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import JiekouHttp.KuaQuMZ;
import duixiang.I_kuaQuMenZhenJiekouReturn;
import uitl.ExcelUtil;
import uitl.Log;
public class TestKuaQuMZ {
@Test
public void MaoYan(){
KuaQuMZ kuaQ = new KuaQuMZ();
try {
// kuaQ.getParm("E:\\测试1.xlsx","Sheet1",0);
I_kuaQuMenZhenJiekouReturn returnDemo= new I_kuaQuMenZhenJiekouReturn();
JSONObject parmReturn = kuaQ.send_I_kuaQ("E:\\测试1.xlsx", "Sheet1", 2);
JSONObject bodyParm = (JSONObject)parmReturn.get("body");
JSONArray bodyTableParm = (JSONArray)bodyParm.get("Table");
String nameReturn = bodyParm.get("name").toString();
ExcelUtil.setExcelFile("E:\\测试1.xlsx", "Sheet1");
String assertDate = ExcelUtil.getCellData(1, 5);
//断言内容根据实际情况,判断用例是否执行成功
Assert.assertEquals(assertDate, nameReturn);
//以上断言通过,则将excel文档中的“测试结果”置为“pass"
ExcelUtil.setCellData(1, 8, "pass", "E:\\测试1.xlsx");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Test
public void ExceptionMessage1(){
KuaQuMZ kuaQ = new KuaQuMZ();
try {
// kuaQ.getParm("E:\\测试1.xlsx","Sheet1",0);
I_kuaQuMenZhenJiekouReturn returnDemo= new I_kuaQuMenZhenJiekouReturn();
JSONObject parmReturn = kuaQ.send_I_kuaQ("E:\\测试1.xlsx", "Sheet1", 3);
JSONObject bodyParm = (JSONObject)parmReturn.get("body");
JSONArray bodyTableParm = (JSONArray)bodyParm.get("Table");
//注:本方法没有写断言和修改测试结果
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Test
public void ExceptionMessage2(){
KuaQuMZ kuaQ = new KuaQuMZ();
try {
// kuaQ.getParm("E:\\测试1.xlsx","Sheet1",0);
I_kuaQuMenZhenJiekouReturn returnDemo= new I_kuaQuMenZhenJiekouReturn();
JSONObject parmReturn = kuaQ.send_I_kuaQ("E:\\测试1.xlsx", "Sheet1", 4);
JSONObject bodyParm = (JSONObject)parmReturn.get("body");
JSONArray bodyTableParm = (JSONArray)bodyParm.get("Table");
//注:本方法没有写断言和修改测试结果
//取接口返回的table中的数据值,存入对象
for(int i=0;i
第二种,代码如下,这种方式遗留一个问题,在最后报告中会呈现。
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import JiekouHttp.KuaQuMZ;
import uitl.ExcelUtil;
import uitl.Log;
public class TestKuaQuMZDataProvider {
@DataProvider(name="loginData")
private Iterator LoginDataProvider() throws IOException {
List result=new ArrayList();
List data = ExcelUtil.getTestListData("E:\\测试1.xlsx", "Sheet1");
Iterator it=data.iterator();
while(it.hasNext()){
result.add(new Object[] { it.next() });
}
return result.iterator();
}
@Test(dataProvider = "loginData")
public void testMaoyan(Object[] sendParm){
KuaQuMZ kuaQ = new KuaQuMZ();
try {
kuaQ.send_I_kuaQDataPro(sendParm);
Log.info("dataProvider");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
7.配置testng的xml,具体参考上上一篇。代码如下:
针对第一个test类配置:
针对第二个test类配置:
多个suite的配置:
8.运行testSuite,查看报告
执行代码后,excel数据如下:
1.本次采用的excel存放请求数据,断言关键字,测试结果,后续可与数据库进行结合,从数据库取出接口需要的请求参数,并且对于接口用例是否通过做的断言,也要与数据库存放的源数据进行比较。
2.对于很多接口,接口地址的配置,后期可采用配置文件来统一做全局变量,统一管理,方便修改