一、前言

前面我们把Jenkins环境、开发环境都搭建好了,现在是不是开始可以写代码了,of course,lets do it!

二、实战开始

看到网上的教学都喜欢拿登录、注册做demo,这次小弟就不走寻常路,来个交易接口作为这次的demo,那么问题来了,交易的前提肯账号必须登录的情况下呀对不对,哼对于咱们开发来说就是一个token/cookie的问题,如果不知道cookie/token是啥的测试人员好好的系统性的多去了解开发的东西,不然多年测试白走一回


  1. 设计思路开始了,首先呢封装一个类调用登录接口获取返回值token,token啥模样呢?咱们看一看瞧一瞧

fiddler一开,接口尽来,看到木有其实就是一串字符码,别在问我fiddler是啥咯哦,不然卸载CSDN吧,emmmm…大哥我开玩笑别打我

2.既然你知道了登录接口,知道了请求域名那么就感觉封装登录接口获取cookie吧

3.新建个类,源码拷贝过去就行,idea会自动帮你引入第三方包

/*** 【封装cookie类】** @author XXX 2019/03/05* */public class getCookie {//获取APP登录 cookie值public static String httpGetAppCookie(String account, String password) throws IOException {HttpPost post = new HttpPost("http://域名/app/uc/login");CloseableHttpClient client = HttpClients.createDefault();//设置请求头post.setHeader("Content-Type","application/x-www-form-urlencoded");//设置请求体List<NameValuePair> paramenters = new ArrayList<NameValuePair>();paramenters.add(new BasicNameValuePair("account",account));paramenters.add(new BasicNameValuePair("pwd",password));HttpEntity requestEntity = new UrlEncodedFormEntity(paramenters);post.setEntity(requestEntity);//执行post请求CloseableHttpResponse response = client.execute(post);//获取的响应内容HttpEntity entity = response.getEntity();String entityString = EntityUtils.toString(entity);//获得cookie值JSONObject json = new JSONObject(entityString);JSONObject jsonData = json.getJSONObject("data");return "token="+jsonData.getString("token");}
}

如果有问我请求体的key为啥是account跟pwd,我抓包工具截图抓出来的哦,真正的实战去看开发接口文档会更方便点,什么?没有接口文档,天杀的开发人员,怼啊老哥
另外小弟得坦白,第31行其实可以把域名,接口都写在application.properties配置文件进行管理的,我偷了个懒,如果大佬们要精益求精那就参考这个吧:https://blog.csdn.net/weixin_40686603/article/details/84751708

4.来吧开始写testng配置文件了,新建个testng.xml

<?xml version="1.0" encoding="UTF-8" ?><suite name="TestSuite"><test name="创建cdk订单"><classes><parameter name="account" value="账号"/><parameter name="password" value="123456"/><parameter name="isPreCreate" value="true"/><parameter name="gameId" value="3"/><parameter name="payApiId" value="10"/><class name="com.test.demo.TestDemo"/></classes></test><listeners><listener class-name="com.test.demo.ExtentTestNGIReporterListener"/></listeners>
</suite>

有人可能会有疑问,parameter是啥玩意儿,我想那你得要系统性的去学习testNG是啥了,懂了你就会用,在这里parameter就是用来运行代码传的参数

5.testng搞定了,那么就开始我们一个demo演示吧

public class TestDemo {@Test@Parameters({"account","password","isPreCreate","gameId","payApiId"})public void testDemo(String account,String password,boolean isPreCreate,long gameId,long payApiId) throws IOException {HttpPost post = new HttpPost("http://appservice.wogame-test.com/app/trade/buyCdkOrder");CloseableHttpClient client = HttpClients.createDefault();//设置请求头post.setHeader("Content-Type","application/x-www-form-urlencoded");post.setHeader("Cookie", GetCookie.getCooike(account,password));//设置请求体List<NameValuePair> paramenters = new ArrayList<NameValuePair>();paramenters.add(new BasicNameValuePair("isPreCreate",String.valueOf(isPreCreate)));paramenters.add(new BasicNameValuePair("gameId",String.valueOf(gameId)));paramenters.add(new BasicNameValuePair("payApiId",String.valueOf(payApiId)));HttpEntity requestEntity = new UrlEncodedFormEntity(paramenters);post.setEntity(requestEntity);//执行post请求CloseableHttpResponse response = client.execute(post);//获得响应内容HttpEntity entity = response.getEntity();String entityString = EntityUtils.toString(entity);//对响应内容断言JSONObject json = new JSONObject(entityString);System.out.println(json);Assert.assertEquals(json.getString("code"),"2000","/app/trade/buyCdkOrder接口异常"+"\n"+String.valueOf(json));}
}

看到了没,testng的参数我给引过来啦,为啥要这样做,因为参数是多变的呀,如果你通过代码写死那你还玩个P接口自动化对不对,所以哦各位老哥搭建这套全栈框架之前,考虑代码的易用性,维护性也是我第一章讲的要思考的问题

6.然后呢?是不是得要运行testng跑接口试试效果啊对不对

舒不舒服,爽不爽?但是呢还没结束哦

7.心细的老哥会发现我testng.xml文件引入了一个ExtentTestNGIReporterListener的监听脚本,那是啥是生成测试报告的玩意儿,不信你看看我跑完接口多了个test-out的文件夹,里面是不是有个测试报告
![在这里插入图片描述
8.ExtentTestNGIReporterListener源码

package com.test.demo;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 = "AutoTest.html";private ExtentReports extent;@Overridepublic 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//怎么样解决csdn无法加载的问题htmlReporter.config().setResourceCDN(ResourceCDN.EXTENTREPORTS);htmlReporter.config().setDocumentTitle("自动化测试报告");htmlReporter.config().setReportName("自动化测试报告");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>() {@Overridepublic 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组合代替报告中的namefor(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, "TestDemo " + 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();}
}

9.老哥舒服不?一站式给你搞定,那么咱就更舒服点打开报告看看

报告长这玩意儿,有人会有疑问为啥是一串字符串,而不是接口名,那是因为我testng.xml没有用group,你加上就OK

10.兄弟这时候你要睡觉,你要休息等明天再写咋整,上传到git上去吧,让Git给你管理让你无后顾之忧

git常用三步操作git add、commit、push好奇的小伙伴可能就会问,这个干嘛的呢?好奇心害死人这样你又得去了解啥是git了哈哈,但是这个一定要会,好东西开源很多公司都用,别面试问你啥都不知道

当然我这边偷懒不规范正常开发人员还得先pull一下代码看下是否有冲突在进行后面操作

11.push完了然后呢?idea没啥变化呀,你的去Git上看,这可是小白步骤我说多了懂得大佬得骂我了

OK搞定,这下接口开发就告一段落了,后面我们该干啥?干你…emmmmmm,阿弥陀佛

后面我们得通过maven编译触发testng执行,然后将Jenkins与git进行结合以及邮件发送测试报告了

全栈搭建接口自动化之接口开发(四)相关推荐

  1. python学全栈还是运维_Python全栈学习——Python基础及Web开发

    原标题:Python全栈学习--Python基础及Web开发 在DevOps火热的敏捷行业中,无论是开发还是运维都在互联网快速发布下练就了一身的本领,微服务下的敏捷开发体系及智能运维体系都在实战中逐步 ...

  2. python自动化接口_Python接口自动化——Web接口

    原标题:Python接口自动化--Web接口 1.2.1 web接口的概念 这里用一个浏览器调试工具捕捉课程管理页面请求作为例子: 当请求页面时,服务器会返回资源,将协议看做是路的话,http可以看做 ...

  3. 全栈工程师实战:从 0 开发云笔记

    专栏亮点 无死角全栈开发:数据库设计.服务端开发.Web 前端开发,三大板块,无死角学习,弥补你的技能短板: 真实项目实战:基于真实项目的实战开发,即学即用,不再迷茫: 规范化开发流程:每个功能,都严 ...

  4. 蚂蚁链开发者实验室:开放全栈工具助力开发者低代码开发

    继元宇宙之后,Web3席卷互联网技术圈.区块链作为这两大趋势下的重要支撑技术,俘获高度关注. 同时伴随着产业区块链的继续深耕,越来越多的开发者看向这个领域,开始更深入去了解.学习.入门区块链. 相比初 ...

  5. 「全栈之路」Web前端开发的后端指南

    前言 在若干次前的一场面试,面试官看我做过 python爬虫/后端 的工作,顺带问了我些后端相关的问题:你觉得什么是后端? 送命题.当时脑瓦特了,答曰:逻辑处理和数据增删改查... 当场被怼得体无完肤 ...

  6. 「真®全栈之路」Web前端开发的后端指南

    前言 在若干次前的一场面试,面试官看我做过python爬虫/后端 的工作,顺带问了我些后端相关的问题:你觉得什么是后端? 送命题.当时脑瓦特了,答曰:逻辑处理和数据增删改查... 当场被怼得体无完肤, ...

  7. Python接口自动化之接口依赖

    VOL 129 28 2020-05 今天距2021年216天 这是ITester软件测试小栈第129次推文 点击上方蓝字"ITester软件测试小栈"关注我,每周一.三.五早上  ...

  8. 【WebGIS全栈】从0到1开发整站——旅游足迹地图网站

    介绍 本专栏起初定位群体为初学者,目标是认识 WebGIS,以及快速上手 WebGIS 前端开发,Demo 也是比较基础的,为了能进阶学习,现在计划提升一下Demo的难度,开发一个完整的足迹网站. 专 ...

  9. 全栈深度学习第2期: 开发套件与工具篇

    一起追剧鸭 简介 Berkeley全栈深度学习追剧计划是由夕小瑶的卖萌屋发起的优质公开课打卡项目,通过微信群为同期追剧的小伙伴提供交流平台.关于该计划的详请见这里. 1. Berkeley深度学习追剧 ...

最新文章

  1. Linux挂载Windows共享目录
  2. Spring中的这些坑,99%的程序员都踩过
  3. 第一课 计算机组成原理(哈工大)
  4. linux下/proc/cpuinfo文件
  5. 华为交换机ACL配置
  6. android 延迟2秒执行_每天30秒让你更懂汽车(10自动变速器2执行装置)
  7. 到底是Java好还是Python好?
  8. 中石油训练赛 - 小说(最短路+二分)
  9. 通过Orchestra以微服务架构的方式生成guid
  10. tmemo 选择消除行_Divi模块,行和部分加入高级动画选项
  11. 数据科学 IPython 笔记本 7.4 Pandas 对象介绍
  12. java实现线性顺序表
  13. SQL Server中CTE的另一种递归方式-从底层向上递归
  14. 亚马逊的冷血文化:虽然备受争议,但颇具力量
  15. Eclipse使用Git上传新项目到GitHub
  16. co作为前缀的意思_注定孤独的前缀|英汉比较教学法·语音思维No.17
  17. c# aes解密 java,C#实现的AES加密解密完整实例
  18. 人工智能应该用在这个地方!
  19. 行走在古道间,看时光深处,
  20. 联想电脑如何修复计算机系统,Lenovo电脑如何用已备份的系统进行一键恢复

热门文章

  1. 史上最全JVM面试题总结
  2. 小米不花一分钱把用户做到10000万的秘密
  3. php+控制器中的全局变量,php中的全局变量引用
  4. 信息系统项目管理师第四版知识摘编:第4章 信息系统管理
  5. Clickhouse数据库引擎Mysql
  6. 苹果M1不仅终结Intel的PC业务,更可能导致X86的覆灭
  7. 类型 状态报告描述 源服务器未能找到目标资源的表示或者是不愿公开一个已经存在的资源表示。
  8. python简单绘图步骤_python画图的两种方法
  9. CPU缓存:L1、L2 和 L3 缓存之间的区别
  10. 日志20120104~0720