-
2021-05-13 17:05:08
手把手教你搭建java接口自动化测试框架(三):基础代码填充
base包下新建TestBase.java
package com.qa.base; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.util.Properties; public class TestBase { //新建测试基类 此类为所有测试类的父类 public Properties pro; //读取配置文件 把读取配置文件的操作卸载构造方法中 我也不知道为什么(摊手 可能这样 效率比较高 public TestBase() { pro = new Properties(); try { FileInputStream fis = new FileInputStream(System.getProperty("user.dir")//获取当前工程目录 + "/src/main/com/qa/config/config.properties");//获取config.properties文件目录 pro.load(fis); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
config包下新建config.properties文件
#项目的根url HOST = https://reqres.in #测试数据excel地址 进阶版本 数据驱动接口测试会用到 我本人目前是不会(lll¬ω¬) #postdata = xxxxx #getdata = xxxx
https://reqres.in是一个提供免费接口调用的网站
restClient包下新建ResClient.java
package com.qa.restClient; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.methods.*; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import java.io.IOException; import java.util.HashMap; import java.util.Map; public class RestClient { //本类中包含post get put delete请求方法 //1 get请求 不带请求头 /** * * @param url 请求地址 * @return * @throws IOException */ public CloseableHttpResponse getApi(String url) throws IOException { //新建一个可关闭的HTTPclient对象 CloseableHttpClient httpClient = HttpClients.createDefault(); //新建get对象 HttpGet get = new HttpGet(url); //执行 get请求 存储返回的响应 CloseableHttpResponse httpResponse = httpClient.execute(get); return httpResponse; } //2 get请求 带有请求头 方法重载 public CloseableHttpResponse getApi(String url , HashMap<String,String> headermap) throws IOException { CloseableHttpClient httpClient = HttpClients.createDefault(); HttpGet httpGet = new HttpGet(url); //加载请求头到HTTP中 for (Map.Entry<String, String> entry : headermap.entrySet()) { httpGet.addHeader(entry.getKey(),entry.getValue()); } CloseableHttpResponse httpResponse = httpClient.execute(httpGet); return httpResponse; } /** * * @param url * @param entityString 设置json 请求参数 * @param headermap 请求头 * @return * @throws IOException */ //3 post请求 public CloseableHttpResponse postApi(String url, String entityString, HashMap<String,String> headermap) throws IOException { CloseableHttpClient httpClient = HttpClients.createDefault(); HttpPost httpPost = new HttpPost(url); //设置payload httpPost.setEntity(new StringEntity(entityString)); //加载请求头对象到 httppost for (Map.Entry<String,String> entry : headermap.entrySet()){ httpPost.addHeader(entry.getKey(),entry.getValue()); } //发送post请求 CloseableHttpResponse httpResponse = httpClient.execute(httpPost); return httpResponse; } //4 Put方法 public CloseableHttpResponse put(String url, String entityString, HashMap<String,String> headerMap) throws ClientProtocolException, IOException { CloseableHttpClient httpclient = HttpClients.createDefault(); HttpPut httpput = new HttpPut(url); httpput.setEntity(new StringEntity(entityString)); for(Map.Entry<String, String> entry : headerMap.entrySet()) { httpput.addHeader(entry.getKey(), entry.getValue()); } //发送put请求 CloseableHttpResponse httpResponse = httpclient.execute(httpput); return httpResponse; } //5 Delete方法 public CloseableHttpResponse delete(String url) throws ClientProtocolException, IOException { CloseableHttpClient httpclient = HttpClients.createDefault(); HttpDelete httpdel = new HttpDelete(url); //发送put请求 CloseableHttpResponse httpResponse = httpclient.execute(httpdel); return httpResponse; } }
到这一步呢请求方法就基本完成了 加上请求内容
就可以进行接口测试了
是不是很想试一试(~ ̄▽ ̄)~请看下集👇
更多相关内容 -
最全面的Java接口自动化测试实战.zip
2021-09-21 07:27:54文件:E:\最全面的Java接口自动化测试实战\project.zip E:\最全面的Java接口自动化测试实战\第10章 项目实战接口开发SpringBoot E:\最全面的Java接口自动化测试实战\第11章 数据持久层框架MyBatis的应用 E:\最全面的... -
最全面的Java接口自动化测试实战.docx
2020-04-02 15:46:00文件:E:\最全面的Java接口自动化测试实战\project.zip E:\最全面的Java接口自动化测试实战\第10章 项目实战接口开发SpringBoot E:\最全面的Java接口自动化测试实战\第11章 数据持久层框架MyBatis的应用 E:\最全面的... -
java接口自动化测试框架及断言详解
2020-08-25 20:57:26主要介绍了java接口自动化测试框架及断言详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 -
Java接口自动化测试框架设计之Get请求方法和测试详解
2020-08-25 20:59:20主要介绍了Java接口自动化测试框架设计 Get请求方法和测试,框架设计我们只是介绍基本的组件,而且框架设计没有想象那么难,一步一步跟着做就会了。这篇我们来演示,如果通过Java代码来实现一个用纯代码实现Http中的... -
Java接口自动化测试
2019-01-21 22:47:35Java+接口自动化测试视频教程,视频高清,讲解易懂,楼主也一直在学习, -
JAVA 接口自动化测试Demo_testng
2017-11-06 16:24:00主要对举例对国家气象局接口自动化测试进行讲解(Get请求及结果断言),以达到自动化测试入门目的,需要有一定的JAVA知识(HTTP相关)。 -
java语言整合API接口自动化测试框架
2020-06-04 14:41:21接口测试框架 https://blog.csdn.net/qq_15283475/article/details/106494544 com.bjci.api #包名 ApiInfoModel.java ## Api类 ExcelUtills.java ##操作excel的类 HandlsUtils.java ##根据judge分发不同的... -
Java接口测试自动化
2019-04-18 12:03:29java接口自动化测试视频教程testng httpclient mock jenkins集成 -
java接口自动化测试源码-wtd-prod:wtd源码版,java版网页和接口自动化测试框架
2021-05-20 01:05:48java接口自动化测试源码 , 技术问题qq群:524212543 , 版本更新 v2.3 2018/01/28 增加发送邮件服务器配置项,修复终端乱码 v2.2 2018/01/20 更新说明文件和democase v2.1 2018/01/09 更新最新chromewebdriver解决... -
JAVA接口自动化实战
2019-08-09 18:18:18JAVA接口自动化实战 网盘链接 -
Java接口自动化测试框架
2019-11-21 12:07:20自动化测试框架 1. 测试框架TestNG 1.1 适合测试人员使用的原因 (1)比Junit涵盖功能更全面的测试框架 (2)Junit更适合隔离性比较强的单元测试 (3)TestNG更适合复杂的集成测试 1.2 基本介绍 (1)基本注解:...一. 自动化测试框架
1. 测试框架TestNG
1.1 适合测试人员使用的原因
(1)比Junit涵盖功能更全面的测试框架
(2)Junit更适合隔离性比较强的单元测试
(3)TestNG更适合复杂的集成测试1.2 基本介绍
(1)基本注解:决定执行顺序
例:
@Test:标记一个类或方法作为测试的一部分
@beforeTest、@afterTest:做前置或后置处理
(2)属性
例:
groups:分组测试
dependsOnGroups:依赖测试
description:描述
(3)测试套件
组织测试类一起执行的或者一组行为的测试用例的集合,由一个XML文件标记2. 测试报告ExtentReport
2.1 添加测试类
ExtentTestNGIReporterListener
2.2 基本配置
在测试套件中 @listener标签下添加监听器
3. HttpClient
一个HTTP客户端编程工具,可用来发送请求、接收响应
4. MyBatis
持久层框架,支持定制化 SQL、存储过程以及高级映射。
可以使用简单的 XML 或注解来配置和映射原生信息。5. MySQL
存储测试用例
二. 编写步骤及文件目录结构
1. 测试用例的表结构设计
2. 基础配置文件设计
2.1 pom.xml:引入第三方依赖包
配置httpclient、json、mybatis、mysql、lombok、extentreports、testng的各种依赖
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>AutoTest</artifactId> <groupId>Chapter</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>Chapter12</artifactId> <dependencies> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.1.2</version> </dependency> <dependency> <groupId>org.json</groupId> <artifactId>json</artifactId> <version>20170516</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.4.4</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.16.14</version> </dependency> <dependency> <groupId>com.relevantcodes</groupId> <artifactId>extentreports</artifactId> <version>2.41.1</version> </dependency> <dependency> <groupId>com.vimalselvam</groupId> <artifactId>testng-extentsreport</artifactId> <version>1.3.1</version> </dependency> <dependency> <groupId>com.aventstack</groupId> <artifactId>extentreports</artifactId> <version>3.0.6</version> </dependency> <dependency> <groupId>org.testng</groupId> <artifactId>testng</artifactId> <version>6.10</version> </dependency> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.0.4</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> </dependencies> </project>
2.2 databaseConfig.xml:数据库配置文件
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <!-- 注册对象的空间命名 --> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <!-- 1.加载数据库驱动 --> <property name="driver" value="com.mysql.cj.jdbc.Driver"/> <!-- 2.数据库连接地址 --> <property name="url" value="jdbc:mysql://localhost:3306/course?serverTimezone=GMT"/> <!-- 数据库用户... --> <property name="username" value="root"/> <!-- 数据库密码... --> <property name="password" value="12345678"/> </dataSource> </environment> </environments> <!-- 注册映射文件:java对象与数据库之间的xml文件路径! --> <mappers> <mapper resource="mapper/SQLMapper.xml"/> </mappers> </configuration>
2.3 application.properties:接口信息配置文件
test.url=http://localhost:8080 #登陆接口uri login.uri=/v1/login
2.4 testng.xml:用以执行所有testng的测试套件
<?xml version="1.0" encoding="UTF-8" ?> <suite name="用户管理系统测试套件"> <test name="用户管理系统测试用例"> <classes> <class name="com.tester.cases.LoginTest"> <methods> <include name="loginTrue"/> <include name="loginFalse"/> </methods> </class> </classes> </test> <listeners> <listener class-name="com.tester.config.ExtentTestNGIReporterListener"/> </listeners> </suite>
2.5 SQLMapper.xml:用以存储所有测试用例的SQL语句
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.tester.model"> <!--获取登陆接口case--> <select id="loginCase" parameterType="Integer" resultType="com.tester.model.LoginCase"> select *from logincase where id=#{id}; </select> </mapper>
3. model层、config层、utils层、cases层
3.1 model层:放置各个接口的数据配置文件+InterfaceName枚举
3.1.1 放置登录接口的数据配置文件LoginCase.java
package com.tester.model; import lombok.Data; @Data public class LoginCase { private int id; private String userName; private String password; private String expected; }
3.1.2 InterfaceName.java
package com.tester.model; public enum InterfaceName { LOGIN }
3.2 Config层:配置信息TestConfig类+ExtentTestNGReportListener类
3.2.1TestConfig类:声明各个测试用例的URL、和之后要用的一些全局变量
package com.tester.config; import lombok.Data; import org.apache.http.client.CookieStore; import org.apache.http.impl.client.DefaultHttpClient; @Data public class TestConfig { //登陆接口uri public static String loginUrl; //声明http客户端 public static DefaultHttpClient defaultHttpClient; //用来存储cookies信息的变量 public static CookieStore store; }
3.2.2 ExtentTestNGReportListener类:测试报告配置
package com.tester.config; import com.aventstack.extentreports.ExtentReports; import com.aventstack.extentreports.ExtentTest; import com.aventstack.extentreports.ResourceCDN; import com.aventstack.extentreports.Status; import com.aventstack.extentreports.model.TestAttribute; import com.aventstack.extentreports.reporter.ExtentHtmlReporter; import com.aventstack.extentreports.reporter.configuration.ChartLocation; import com.aventstack.extentreports.reporter.configuration.Theme; import org.testng.*; import org.testng.xml.XmlSuite; import java.io.File; import java.util.*; public class ExtentTestNGIReporterListener implements IReporter { //生成的路径以及文件名 private static final String OUTPUT_FOLDER = "test-output/"; private static final String FILE_NAME = "index.html"; private ExtentReports extent; @Override public void generateReport(List<XmlSuite> xmlSuites, List<ISuite> suites, String outputDirectory) { init(); boolean createSuiteNode = false; if(suites.size()>1){ createSuiteNode=true; } for (ISuite suite : suites) { Map<String, ISuiteResult> result = suite.getResults(); //如果suite里面没有任何用例,直接跳过,不在报告里生成 if(result.size()==0){ continue; } //统计suite下的成功、失败、跳过的总用例数 int suiteFailSize=0; int suitePassSize=0; int suiteSkipSize=0; ExtentTest suiteTest=null; //存在多个suite的情况下,在报告中将同一个一个suite的测试结果归为一类,创建一级节点。 if(createSuiteNode){ suiteTest = extent.createTest(suite.getName()).assignCategory(suite.getName()); } boolean createSuiteResultNode = false; if(result.size()>1){ createSuiteResultNode=true; } for (ISuiteResult r : result.values()) { ExtentTest resultNode; ITestContext context = r.getTestContext(); if(createSuiteResultNode){ //没有创建suite的情况下,将在SuiteResult的创建为一级节点,否则创建为suite的一个子节点。 if( null == suiteTest){ resultNode = extent.createTest(r.getTestContext().getName()); }else{ resultNode = suiteTest.createNode(r.getTestContext().getName()); } }else{ resultNode = suiteTest; } if(resultNode != null){ resultNode.getModel().setName(suite.getName()+" : "+r.getTestContext().getName()); if(resultNode.getModel().hasCategory()){ resultNode.assignCategory(r.getTestContext().getName()); }else{ resultNode.assignCategory(suite.getName(),r.getTestContext().getName()); } resultNode.getModel().setStartTime(r.getTestContext().getStartDate()); resultNode.getModel().setEndTime(r.getTestContext().getEndDate()); //统计SuiteResult下的数据 int passSize = r.getTestContext().getPassedTests().size(); int failSize = r.getTestContext().getFailedTests().size(); int skipSize = r.getTestContext().getSkippedTests().size(); suitePassSize += passSize; suiteFailSize += failSize; suiteSkipSize += skipSize; if(failSize>0){ resultNode.getModel().setStatus(Status.FAIL); } resultNode.getModel().setDescription(String.format("Pass: %s ; Fail: %s ; Skip: %s ;",passSize,failSize,skipSize)); } buildTestNodes(resultNode,context.getFailedTests(), Status.FAIL); buildTestNodes(resultNode,context.getSkippedTests(), Status.SKIP); buildTestNodes(resultNode,context.getPassedTests(), Status.PASS); } if(suiteTest!= null){ suiteTest.getModel().setDescription(String.format("Pass: %s ; Fail: %s ; Skip: %s ;",suitePassSize,suiteFailSize,suiteSkipSize)); if(suiteFailSize>0){ suiteTest.getModel().setStatus(Status.FAIL); } } } // for (String s : Reporter.getOutput()) { // extent.setTestRunnerOutput(s); // } extent.flush(); } private void init() { //文件夹不存在的话进行创建 File reportDir= new File(OUTPUT_FOLDER); if(!reportDir.exists()&& !reportDir .isDirectory()){ reportDir.mkdir(); } ExtentHtmlReporter htmlReporter = new ExtentHtmlReporter(OUTPUT_FOLDER + FILE_NAME); // 设置静态文件的DNS //怎么样解决cdn.rawgit.com访问不了的情况 htmlReporter.config().setResourceCDN(ResourceCDN.EXTENTREPORTS); htmlReporter.config().setDocumentTitle("api自动化测试报告"); htmlReporter.config().setReportName("api自动化测试报告"); htmlReporter.config().setChartVisibilityOnOpen(true); htmlReporter.config().setTestViewChartLocation(ChartLocation.TOP); htmlReporter.config().setTheme(Theme.STANDARD); htmlReporter.config().setCSS(".node.level-1 ul{ display:none;} .node.level-1.active ul{display:block;}"); extent = new ExtentReports(); extent.attachReporter(htmlReporter); extent.setReportUsesManualConfiguration(true); } private void buildTestNodes(ExtentTest extenttest, IResultMap tests, Status status) { //存在父节点时,获取父节点的标签 String[] categories=new String[0]; if(extenttest != null ){ List<TestAttribute> categoryList = extenttest.getModel().getCategoryContext().getAll(); categories = new String[categoryList.size()]; for(int index=0;index<categoryList.size();index++){ categories[index] = categoryList.get(index).getName(); } } ExtentTest test; if (tests.size() > 0) { //调整用例排序,按时间排序 Set<ITestResult> treeSet = new TreeSet<ITestResult>(new Comparator<ITestResult>() { @Override public int compare(ITestResult o1, ITestResult o2) { return o1.getStartMillis()<o2.getStartMillis()?-1:1; } }); treeSet.addAll(tests.getAllResults()); for (ITestResult result : treeSet) { Object[] parameters = result.getParameters(); String name=""; //如果有参数,则使用参数的toString组合代替报告中的name for(Object param:parameters){ name+=param.toString(); } if(name.length()>0){ if(name.length()>50){ name= name.substring(0,49)+"..."; } }else{ name = result.getMethod().getMethodName(); } if(extenttest==null){ test = extent.createTest(name); }else{ //作为子节点进行创建时,设置同父节点的标签一致,便于报告检索。 test = extenttest.createNode(name).assignCategory(categories); } //test.getModel().setDescription(description.toString()); //test = extent.createTest(result.getMethod().getMethodName()); for (String group : result.getMethod().getGroups()) test.assignCategory(group); List<String> outputList = Reporter.getOutput(result); for(String output:outputList){ //将用例的log输出报告中 test.debug(output); } if (result.getThrowable() != null) { test.log(status, result.getThrowable()); } else { test.log(status, "Test " + status.toString().toLowerCase() + "ed"); } test.getModel().setStartTime(getTime(result.getStartMillis())); test.getModel().setEndTime(getTime(result.getEndMillis())); } } } private Date getTime(long millis) { Calendar calendar = Calendar.getInstance(); calendar.setTimeInMillis(millis); return calendar.getTime(); } }
3.3 utils层: 抽取公用的方法ConfigFile类+DatabaseUtil类
3.3.1 ConfigFile类:对各个测试用例的URL进行赋值
package com.tester.utils; import com.tester.model.InterfaceName; import java.util.Locale; import java.util.ResourceBundle; public class ConfigFile { public static ResourceBundle bundle=ResourceBundle.getBundle("application", Locale.CHINA); public static String getUrl(InterfaceName name){ String address=bundle.getString("test.url"); String uri=""; String testUrl; if(name==InterfaceName.LOGIN){ uri=bundle.getString("login.uri"); } testUrl=address+uri; return testUrl; } }
3.3.2 DatabaseUtil类:配置一个getSqlSession()方法
作用是执行配置文件SQLMapper中的SQL语句
package com.tester.utils; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import java.io.IOException; import java.io.Reader; public class DatabaseUtil { public static SqlSession getSqlSession() throws IOException { //获取配置的资源文件 Reader reader= Resources.getResourceAsReader("databaseConfig.xml"); //得到SqlSessionFactory,使用类加载器加载xml文件 SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(reader); //得到sqlsession对象,这个对象就能执行配置文件中的sql语句啦 SqlSession session=factory.openSession(); return session; } }
3.4 cases层:用来放接口的测试用例
package com.tester.cases; import com.tester.config.TestConfig; import com.tester.model.InterfaceName; import com.tester.model.LoginCase; import com.tester.utils.ConfigFile; import com.tester.utils.DatabaseUtil; import org.apache.http.HttpResponse; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.util.EntityUtils; import org.apache.ibatis.session.SqlSession; import org.json.JSONObject; import org.testng.Assert; import org.testng.annotations.BeforeTest; import org.testng.annotations.Test; import java.io.IOException; public class LoginTest { @BeforeTest(groups = "loginTrue",description = "测试准备工作,获取HttpClient对象") public void beforeTest(){ TestConfig.getUserInfoUrl= ConfigFile.getUrl(InterfaceName.GETUSERINFO); TestConfig.getUserListUrl=ConfigFile.getUrl(InterfaceName.GETUSERLIST); TestConfig.addUserUrl=ConfigFile.getUrl(InterfaceName.ADDUSERINFO); TestConfig.loginUrl=ConfigFile.getUrl(InterfaceName.LOGIN); TestConfig.updateUserInfoUrl=ConfigFile.getUrl(InterfaceName.UPDATEUSERINFO); TestConfig.defaultHttpClient=new DefaultHttpClient(); } @Test(groups = "loginTrue",description = "用户成功登陆接口") public void loginTrue() throws IOException { SqlSession session= DatabaseUtil.getSqlSession(); LoginCase loginCase=session.selectOne("loginCase",1); System.out.println(loginCase.toString()); System.out.println(TestConfig.loginUrl); //下边的代码为写完接口的测试代码 String result=getResult(loginCase); //处理结果,就是判断返回结果是否符合预期 Assert.assertEquals(loginCase.getExpected(),result); } @Test(groups = "loginFalse",description = "用户登录接口失败") public void loginFalse() throws IOException { SqlSession session=DatabaseUtil.getSqlSession(); LoginCase loginCase=session.selectOne("loginCase",2); System.out.println(loginCase.toString()); System.out.println(TestConfig.loginUrl); //下边的代码为写完接口的测试代码 String result=getResult(loginCase); //处理结果,就是判断返回结果是否符合预期 Assert.assertEquals(loginCase.getExpected(),result); } private String getResult(LoginCase loginCase) throws IOException { //下边的代码为写完接口的测试代码 HttpPost post=new HttpPost(TestConfig.loginUrl); JSONObject param=new JSONObject(); param.put("userName",loginCase.getUserName()); param.put("password",loginCase.getPassword()); //设置请求头信息,设置header post.setHeader("content-type","application/json"); //将参数信息添加到方法中 StringEntity entity=new StringEntity(param.toString(),"utf-8"); post.setEntity(entity); //声明一个对象来进行响应结果的存储 String result; //执行post方法 HttpResponse response=TestConfig.defaultHttpClient.execute(post); //获取响应结果 result= EntityUtils.toString(response.getEntity(),"utf-8"); System.out.println(result); TestConfig.store=TestConfig.defaultHttpClient.getCookieStore(); return result; } }
-
接口自动化测试框架
2018-04-02 22:38:53搭建接口自动化测试框架 搭建接口自动化测试框架 搭建接口自动化测试框架 搭建接口自动化测试框架 -
手把手教你搭建java接口自动化测试框架(四):断言、生成测试报告
2021-05-13 21:14:54手把手教你搭建java接口自动化测试框架(四):断言、生成测试报告 上一集说到post和Get请求,请求后得到的响应(即接口返回值)是我们想要的吗 比如网站上get接口文档说明 : “data”: [ { “id”: 7, “email”: ...手把手教你搭建java接口自动化测试框架(四):断言、生成测试报告
上一集说到post和Get请求,请求后得到的响应(即接口返回值)是我们想要的吗
比如网站上get接口文档说明 :
“data”: [
{
“id”: 7,
“email”: “michael.lawson@reqres.in”,
“first_name”: “Michael”,
“last_name”: “Lawson”,
“avatar”: “https://reqres.in/img/faces/7-image.jpg”
}
我们得到的接口返回值,id=7时first_name是Michael吗,last_name是Lawson吗这就需要用到断言
在引入断言之前 有的伙计可能会觉得疑惑
接口得到的response 是json格式 我们将其转化成字符串打印出来
怎么进行对比呢
这 就需要用智慧写出一个提取json字符串值的工具类( ̄▽ ̄)utils包下新建getJsonValueUtil.java
package com.qa.utils; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; public class getJsonValueUtil { //Json解析 public static String getValueByJpath(JSONObject responseJson, String jpath) { Object obj = responseJson; for(String s : jpath.split("/")) { if(!s.isEmpty()) { if(!(s.contains("[") || s.contains("]"))) { obj = ((JSONObject) obj).get(s); }else if(s.contains("[") || s.contains("]")) { obj =((JSONArray)((JSONObject)obj).get(s.split("\\[")[0])).get(Integer.parseInt(s.split("\\[")[1].replaceAll("]", ""))); } } } return obj.toString(); } }
这个获取json value的方法是什么意思呢
我们来看json字符串的的组成
这个方法主要可以查询两种json值
第一 total=2这种,在json串的第一层,是一个json对象,想要获取total的值,只需要传入其jpath(“total”)就可获取其值,返回结果是12第二 first_name这种,在data数组中,data属于json数组,不能直接拿值,只能遍历,红线圈出来的是data数组第一个 ,所以查询时jpath是"data[0]/first_name",返回结果是Michael
既然拿到了json里面的值 我们就可以使用断言进行判断啦
修改之前的GetTest01.java 加入断言内容@Test public void getListUsers() throws IOException { restClient = new RestClient(); response = restClient.getApi(url); //获取响应内容 String responseString = EntityUtils.toString(response.getEntity(),"UTF-8"); //创建JSON对象 把得到的响应字符串 序列化成json对象 JSONObject responseJson = JSONObject.parseObject(responseString); System.out.println("response json---->" + responseJson); //判断得到的结果是否正确 //首先判断网站是否成功响应 先获取状态码 int statusCode = response.getStatusLine().getStatusCode(); //获取到的状态码和200 对比 如果相等就说明网站响应成功 Assert.assertEquals(statusCode,200,"网页成功响应"); //然后判断得到的相应内容是否和接口文档一致 //比如 page=2 per_page=6 total=12是否正确 //调用utils里面写好的 获取json value的方法 String get_total = getJsonValueUtil.getValueByJpath(responseJson,"total"); String get_first_name = getJsonValueUtil.getValueByJpath(responseJson,"data[0]/first_name"); //断言研判接口返回值是否与预期一致 Assert.assertEquals(get_total,"12","获取信息总数非12条"); Assert.assertEquals(get_first_name,"Michael","用户名字不是Michael"); }
举得两个例子都成功了
想看失败效果的可以自己试一试那么getListUsers这一个测试用例算是通过了 我们来看控制台
可以看到运行了1个用例 失败0 跳过0
控制台有一个左下箭头 点击导出报告
导出后看见报告(奇丑无比)让大家失望了
肯定有伙计就会问 就这?这就是测试报告?
当然不是(~ ̄▽ ̄)~我们在一开始就引了extentreport包,特地来美化测试报告的,测试报告怎么会如此不美观大方呢
继续往下看IDEA跟eclipse不一样 需要设置一下才能看见测试报告
点击控制台
Listners–>Use default reporters ---->apply -->ok
再次运行用例 自动生成test-output文件夹 .html文件就是测试报告啦(●’◡’●)
惊不惊喜意不意外╮(╯▽╰)╭
虽然不好意思说 肯定还是觉得很吃藕 对不对!
当然这个报告是需要继续美化的 具体操作请看下集👇
-
Java接口自动化测试框架设计-4-POST请求方法封装过程和测试
2018-05-22 23:48:38这个接口自动化测试框架到目前为止,我们已经完成了Get请求的封装和必要的工具类的支持。...所以,这个Java接口自动化测试框架的核心就是Get和POST请求方法的封装过程。 1.POST接口举例浏览器打开https://re...这个接口自动化测试框架到目前为止,我们已经完成了Get请求的封装和必要的工具类的支持。接下来这篇,我来介绍如何完成POST请求的封装过程。一般来说,在一个项目中,接口测试很多时候就是测试Get和POST方法,其他的请求方式的接口很少,占的比重几乎不计。所以,这个Java接口自动化测试框架的核心就是Get和POST请求方法的封装过程。
1.POST接口举例
浏览器打开https://reqres.in/,下拉一屏。点击第一个POST请求,这个接口的介绍信息如下。
这个接口的作用是创建用户,参数是一个json类型的数据,一个name一个job,两个JSON对象。发送请求之后,返回的JSON数据有name和job和id,以及创建时间这几个数据。
2.Postman手动实现
我们先在本地postman环境,先来手动测试实现下这个post接口的请求过程。
这个post接口请求还是比较简单,很容易在postman上实现该请求。
3.Java代码自动化实现
我们已经可以正确地在postman上实现创建用户这个接口的手动测试,那么我们想要这个过程自动化实现,如何做呢。下面我在RestClient.java封装了两个方法,一个是带请求头信息的Get请求,一个是带请求头信息的POST请求方法。这篇,了解了POST请求方法,带请求头的Get方法封装就很好理解。
package com.qa.restclient; import java.io.IOException; import java.util.HashMap; import java.util.Map; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; 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; public class RestClient { //1. Get 请求方法 public CloseableHttpResponse get(String url) throws ClientProtocolException, IOException { //创建一个可关闭的HttpClient对象 CloseableHttpClient httpclient = HttpClients.createDefault(); //创建一个HttpGet的请求对象 HttpGet httpget = new HttpGet(url); //执行请求,相当于postman上点击发送按钮,然后赋值给HttpResponse对象接收 CloseableHttpResponse httpResponse = httpclient.execute(httpget); return httpResponse; } //2. Get 请求方法(带请求头信息) public CloseableHttpResponse get(String url,HashMap<String,String> headermap) throws ClientProtocolException, IOException { //创建一个可关闭的HttpClient对象 CloseableHttpClient httpclient = HttpClients.createDefault(); //创建一个HttpGet的请求对象 HttpGet httpget = new HttpGet(url); //加载请求头到httpget对象 for(Map.Entry<String, String> entry : headermap.entrySet()) { httpget.addHeader(entry.getKey(), entry.getValue()); } //执行请求,相当于postman上点击发送按钮,然后赋值给HttpResponse对象接收 CloseableHttpResponse httpResponse = httpclient.execute(httpget); return httpResponse; } //3. POST方法 public CloseableHttpResponse post(String url, String entityString, HashMap<String,String> headermap) throws ClientProtocolException, IOException { //创建一个可关闭的HttpClient对象 CloseableHttpClient httpclient = HttpClients.createDefault(); //创建一个HttpPost的请求对象 HttpPost httppost = new HttpPost(url); //设置payload httppost.setEntity(new StringEntity(entityString)); //加载请求头到httppost对象 for(Map.Entry<String, String> entry : headermap.entrySet()) { httppost.addHeader(entry.getKey(), entry.getValue()); } //发送post请求 CloseableHttpResponse httpResponse = httpclient.execute(httppost); return httpResponse; } }
然后,我们需要写一个TestNG测试用例来测试下这个封装的post方法好不好用。由于我们去前面几篇文章介绍了TestNG测试get方法的代码,这里我们就直接拷贝和修改部分代码就行。
在写测试用例之前,我们需要提前准备好json数据,一般来说,在Java中JSON数据都是放在JAVA Bean类中,通过JSON把高级对象序列化成JSON对象。
在src/main/java中新建包:com.qa.data,然后新建一个Users.java,这个命名就参考接口的url单词就行。在postman或者网站该post方法,我们知道,需要name和job这两个json对象。我们新建一个bean类,同alt+shift+s,然后选择生成构造方法和set和get方法。
package com.qa.data; public class Users { private String name; private String job; public Users() { super(); } public Users(String name, String job) { super(); this.name = name; this.job = job; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getJob() { return job; } public void setJob(String job) { this.job = job; } }
好了,在src/test/java下的com.qa.tests我们新建一个POST测试用例,现在我们的TestNG测试类代码如下:
package com.qa.tests; import java.io.IOException; import java.util.HashMap; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.util.EntityUtils; import org.testng.Assert; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.qa.base.TestBase; import com.qa.data.Users; import com.qa.restclient.RestClient; import com.qa.util.TestUtil; public class PostApiTest extends TestBase { TestBase testBase; String host; String url; RestClient restClient; CloseableHttpResponse closeableHttpResponse; @BeforeClass public void setUp() { testBase = new TestBase(); host = prop.getProperty("HOST"); url = host + "/api/users"; } @Test public void postApiTest() throws ClientProtocolException, IOException { restClient = new RestClient(); //准备请求头信息 HashMap<String,String> headermap = new HashMap<String,String>(); headermap.put("Content-Type", "application/json"); //这个在postman中可以查询到 //对象转换成Json字符串 Users user = new Users("Anthony","tester"); String userJsonString = JSON.toJSONString(user); //System.out.println(userJsonString); closeableHttpResponse = restClient.post(url, userJsonString, headermap); //验证状态码是不是200 int statusCode = closeableHttpResponse.getStatusLine().getStatusCode(); Assert.assertEquals(statusCode, RESPNSE_STATUS_CODE_201,"status code is not 201"); //断言响应json内容中name和job是不是期待结果 String responseString = EntityUtils.toString(closeableHttpResponse.getEntity()); JSONObject responseJson = JSON.parseObject(responseString); //System.out.println(responseString); String name = TestUtil.getValueByJPath(responseJson, "name"); String job = TestUtil.getValueByJPath(responseJson, "job"); Assert.assertEquals(name, "Anthony","name is not same"); Assert.assertEquals(job, "tester","job is not same"); } }
建议,在写测试用例过程中,需要和postman上的请求结果参考,特别是Headers这里的键值对。这里留一个作业,上面我写了一个Get带请求头的封装方法,你可以对照postman中的请求头去写一个单元测试用例去测试下这个带headers的Get方法。
目前,Java接口自动化测试框架的核心部分,http请求方法的封装已经完成。接下里还有测试日志,测试报告,或者其他需要抽取优化的模块去完成。
-
AutoTest:基于Java的接口自动化测试
2021-05-03 05:01:37AutoTest 基于Java的接口自动化测试 -
手把手教你搭建java接口自动化测试框架(四):get、post方法实现
2021-05-13 17:32:34手把手教你搭建java接口自动化测试框架(四):get、post方法实现 看完了三篇 各种配置、代码 到这一篇终于可以进行实战了 是骡子是马拉出来溜溜( •̀ ω •́ )✧ 执行get请求 tests包下新建GetTest01.java ... -
灵活轻巧的java接口自动化测试实战
2020-05-19 11:01:59无论是自动化测试还是自动化部署,撸码肯定少不了,所以下面的基于java语言的接口自动化测试,要想在业务上实现接口自动化,前提是要有一定的java基础。 如果没有java基础,也没关系。这里小编也为大家提供了一套... -
手把手教你搭建java接口自动化测试框架(一):前期准备工作
2021-05-13 14:38:18手把手教你搭建java接口自动化测试框架(一):前期准备工作 本人也是接口自动化测试框架小白 最近跟着一些教程成功搭建了自己的接口自动化测试框架 该框架基于IDEA+TestNG+extentreport可完成基本的post、get请求 ... -
Java接口自动化测试框架学习(三)
2018-09-14 16:53:32前面项目已创建好,依赖包添加完成,testng也已添加 项目结构如下: 1.设计配置文件 在src/main/java下新建一个包:...然后在src/main/java下新建一个包:com.qa.base,新建一个TestBase.java,这个... -
基于java+Selenium实现的Web和接口自动化测试工具
2016-10-09 11:39:44个人觉得这个工具比任何自动化测试框架都好使,使用关键字和数据双驱动,不需要写一行代码,无需维护脚本,只需要维护用例数据。Web元素只需要在Chrome中复制xPath即可,定位非常高效。 工具安全无木马,目的只为... -
Java接口自动化测试框架设计-1-开发环境的搭建
2018-05-21 23:58:05废话不多说,刚开始,尽量详细,通过一步一步,手把手教会你搭建接口自动化测试的基础项目环境。 一.前提条件 我这里来一个约定,有以下前提条件。1.本机环境安装了maven并配置环境变量2.本机环境安装了Eclipse... -
Java接口自动化测试框架设计-6-日志输出和常用代码提取成方法-2018-08-21更新
2018-05-26 17:30:44前面说过了,如果你稍微懂得TestNG这个单元测试框架,到目前这个简单的Java接口自动化测试框架主体的骨架部分已经完成设计并实现。这篇,继前篇的基础上,把测试用例中获取响应状态码和响应数据转换成JSON格式这些... -
Java接口自动化测试框架学习(一)
2018-08-14 16:58:483.本机环境安装了Java jdk 8版本 maven环境的安装: 1.下载Maven http://maven.apache.org/download.cgi 2.配置环境变量 2.1解压至C盘 2.2打开环境配置,如下: 2.3配置路径,Maven官网说,可以配置一... -
Java接口自动化测试之「Mock接口平台」,让你的自动化更提前
2018-10-23 14:35:48前言:目前Mock技术已经比较成熟,在日常的工作中Mock也可以给我们带来很大的遍历,本篇文章将会使用Moco框架,一步一步搭建一套Mock Server,使得接口的自动化测试更加的提前,也能够使得前后端分离。 共识与痛点... -
Java接口自动化测试使用ExtentReports生成测试报告
2019-06-26 23:31:07项目下会自动生成一个 test-output 文件夹,下面2个html文件就是本次执行的测试报告。 5、查看测试报告 emailable-report.html 简单报告,看起来没什么感觉,查看另一个 report.html -
api接口自动化测试工具
2018-03-13 22:30:09Wisdom RESTClient https://github.com/Wisdom-Projects/rest-client -
手把手教你搭建java接口自动化测试框架(二):框架介绍、pom.xml配置
2021-05-13 15:57:51手把手教你搭建java接口自动化测试框架(二):框架介绍、pom.xml配置 接口自动化框架组成: src/main/java包下新建com.qa.base等等 存放不同的代码 配置pom.xml 要做接口测试 就需要用到各种各样的插件。需要再pom... -
接口自动化测试之获取token
2018-08-07 10:00:55代码简单明了,可以复制粘贴、很实用,包含了两种获取方式