精通api接口测试,接口分类,接口架构,http,webservice,dubbo接口协议, ...

打印 上一主题 下一主题

主题 1047|帖子 1047|积分 3141

一,【什么是接口测试?为什么要作接口测试】

接口口测试和接口自动化测试一直都是很多人杂乱的概念。以是搞清楚2个的概念是很重要的一件事情。
接口:一段具备逻辑处置处罚功能的步调代码组成的,可被其他方法、服务或应用所利用。
对于调用接口的那一方,可以把接口看做一只黑匣子,只必要负责按约定传入参数,再吸收返回的数据,而不必要知道黑匣子里的逻辑。
1.接口的作用



  • 1.体系与体系之间的调用。比如银联会提供付出接口给负责三方付出的应用步调调用,应用步调在用户发起付出请求时,将相干的必要参数值通过付出接口传给银联服务器,银联服务器处置处罚完成之后会调用应用步调方的回调接口,返回付出处置处罚结果。
  • 2.前端应用对后端服务的调用。比如应用步调调用服务器端的接口,服务器端调用DAO[data access object 数据访问对象]的接口。以某体系来看,应用步调本身重要包括2部分:一是交互,二是数据展示。应用步调通过数据访问对象的接口从数据库中获取到相应的数据,服务器端接口在将数据做相应的处置处罚并终极返回给应用步调,应用步调将其展示出来。
  • 3.服务与服务之间的调用。比如,注册用户,会先调用查询用户信息的服务,目标是检查是否已注册。如果返回已注册,则负责注册用户的接口就会将该结果返回到前段页面。
  • 接口测试是测试体系组件间接口的一种测试,重要用于检测外部体系与体系之间以及内部各个子体系之间的交互点。测试的重点是检查数据的交互、传递和控制管理过程,以及体系间的相互逻辑依赖关系等。
2.为什么要做接口测试



  • 1.只靠前端测试很难确保很高的覆盖率。接口测试,可以模仿出各种范例的入参,包括一些在前端模仿不出来的入参,还能根据接口文档的界说,计划出相对美满的入参值,在接口层保证质量,剩余的绝大多数题目就是应用步调自身的交互和数据展示题目。
  • 2.接口测试相对于交互界面测试和功能测试来说,更轻易实现自动化,执行起来比较稳固,维护成本也比较低。
  • 3.接口自动化适用于回归测试等,可以淘汰人工回归测试的人力成本。
  • 4.前、后端体系分离,从安全层面来说,只依赖前端进行不能满足安全要求,绕过前端相对轻易,以是必要后端同样进行输入校验,只能依赖接口测试去验证了。
3.接口都有哪些范例?

接口一般分为两种:1.步调内部的接口 2.体系对外的接口
体系对外的接口:比如你要从别的网站或服务器上获取资源或信息,别人肯定不会把数据库共享给你,他只能给你提供一个他们写好的方法来获取数据,你引用他提供的接口就能利用他写好的方法,从而到达数据共享的目标。
步调内部的接口:方法与方法之间,模块与模块之间的交互,步调内部抛出的接口,比如bbs体系,有登录模块、发帖模块等等,那你要发帖就必须先登录,那么这两个模块就得有交互,它就会抛出一个接口,供内部体系进行调用。
二,【接口测试的分类】

接口的分类:

1.webservice接口
2.http api接口
webService接口是走soap协议通过http传输,请求报文和返回报文都是xml格式的,我们在测试的时间都用通过工具才能进行调用测试。
webService走如soup、rmi、rpc协议
http api接口是走http协议,通过路径来区分调用的方法,请求报文都是key-value情势的,返回报文一般都是json串,有get和post等方法,这也是最常用的两种请求方式。
json是一种通用的数据范例,所有的语言都熟悉它。(json的本质是字符串,他与其他语言无关,只是可以经过稍稍加工可以转换成其他语言的数据范例,比如可以转换成Python中的字典,key-value的情势,可以转换成JavaScript中的原生对象,可以转换成java中的类对象等。)
http和webservice接口区别:

httpservice通过post和get得到你想要的东西
webservice就是利用soap协议得到你想要的东西,相比httpservice能处置处罚些更加复杂的数据范例
http协议传输的都是字符串了,webservice则是包装成了更复杂的对象。
 三,【理解http,webservice,Dubbo接口协议】
 



一、接口

API: Application Programming Interface, 应用步调可编程接口
1)接口分类

硬件接口:具有毗连功能、适配。两个硬件设备之间的毗连方式(比如鼠标和电脑通过USB接口毗连)
软件接口:软件步调之间数据交互的通道(用户界面是软件接口)
2)软件接口分类

步调内部接口:是客户端与服务器的接口,用来实现客户端和服务器的数据传递
外部接口:比如通过第三方登录,第三方付出,通过调用外部接口并返回当前的体系
3)常见的接口协议

webService接口:利用soup协议通过http传输,请求报文和返回报文都是xml格式的,常用测试工具有soupUI
http协议接口:现在利用最广泛的,利用HTTP协议来传输数据,常见的请求方法有get、post等,常用测试工具有postman、jmeter
dubbo、 websocket、 ws://...、 ftp://等协议。
4)接口测试

本质是基于某种协议,发送一个请求给服务器,然后服务器返回一个响应,然后对响应数据进行分析,判断是否与我们预期的返回划一,从而验证功能是否正确。
二、HTTP协议解读

1)http协议:超文本传输协议

2)https:简朴的来说,就是http的安全版,在http下到场了SSL层(SSL重要用户web的安全传输协议)

3)http的默认端口号是:80 ,默认的端口在url可以不加

 https的默认端口号是:443 ,默认的端口在url可以不加
4)HTTP请求过程

客户端:PC端的应用步调 浏览器 APP 小步调
HTTP通信:客户端发送给服务器的请求信息
       服务器返回给客户端的响应信息
客户端:前端----->主动请求。能够发起对应的请求的客户端。
服务端:后端----->被动接受。


  

  扩展URL:


5)HTTP请求信息

  1. 请求行: 请求方法/请求网址/协议版本
  2. 请求头部:header
  3. host
  4. connection
  5. upgrade-insecure-requests
  6. user-agent:用户代理,通过客户端代理
  7. referer
  8. accept-encoding
  9. cookie
  10. 备注:域名和IP地址之间是映射关系,域名是为了好记
复制代码
  1. 请求数据:
复制代码

6)HTTP响应信息

  1. 状态行:状态码
  2. 消息报头:
  3.   content-type:返回的数据格式
  4.     test/html
  5.     application/json
  6.     application/xml
  7. 响应正文:
复制代码
7)HTTP响应状态码

  1. 状态码 含义 客户端client 服务器端server
  2. 1xx | Informational 信息 啥都不用做,知道就好 信息收到了,后续会处理
  3. 2xx | Successful 成功 啥都不用做,知道就好 请求已正确处理
  4. 3xx | Redirection 重定向 重新请求返回的新地址 client需要的内容,由于一些原因,比如地址已发生变化了,然后返回该内容的新地址
  5. 4xx | 客户端的错误 确保用正确的参数和信息正确,重新请求 请求已正确处理
  6. 5xx | 服务器端的错误 都无需操作,服务器端改了bug后,重新发送请求 服务器端的代码的bug导致了出错
复制代码
8)HTTP请求方法


get和post的区别:
a)应用场景不同
  get获取资源
  post提交数据,创建新的数据/对已有数据的修改

b)参数存放 
  get请求的参数都可以显示在浏览器网址上,通过?param=value【即query string方式】查询字符串
  post可以利用query string,但是通常不这么做,通常放到body请求体当中
c)安全性
get和post并没有谁更安全,抓包都是可以看到里面的数据,网上说的post更安全是因为数据放到了body当中,肉眼看不到而已, 但着实也是不安全的,而get请求是直接在URL中肉眼可以看到
备注:加密与请求方法没关系,什么东西都是可以加密的
【WebService协议】

http 和 webservice 都是基于TCP/IP协议的应用层协议
webservice是基于http的soap协议传输数据 webservice=soap=http+xml,webservice协议就是有http+xml组成的,其中xml中会用到wsdl,wsdl是描述语言xml中的一种格式。
socket是基于TCP/IP的传输协议,是对TCP/IP协议的封装
socket和TCP都是基于TCP/IP传输层协议
注:Restful是一种接口规范,而不是接口协议,restful接口规范中也会用到http协议。
 因现在大部分会用http协议不用webservice协议,故没有现实操作,只是转载来了解理论。
一. WSDL WebService的创建:

1.创建【Web Service Project】:


image.png
WebServices Framework要选JAX-WS:


image.png
2.写一个简朴的测试用例:

package com.webservice;
public class WebService{
  1. public String printData(String printerName){
  2. String strRet = "Welcome to use WebService, " + printerName;
  3. System.out.println("Print from WebService:" + strRet);
  4. return strRet;
  5. }
复制代码
3.发布Web Service:
点击工具栏的New Web Service:




image.png
Strategy选择第二个(Create web service from Java class):


image.png
勾选【Generate WSDL in project】:



image.png
点击【Finish】后,体系会在WEB-INF/wsdl下天生两个文件:

  1. image.png
  2. WebServiceService.wsdl:这个文件是用来描述Web Service内容的
  3. <?xml version="1.0" encoding="UTF-8"?>
  4. <definitions xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://webservice.com/" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="WebServiceService" targetNamespace="http://webservice.com/">
  5. <types>
  6. <xsd:schema>
  7. <xsd:import namespace="http://webservice.com/" schemaLocation="WebServiceService_schema1.xsd"/>
  8. </xsd:schema>
  9. </types>
  10. <message name="printData">
  11. <part element="tns:printData" name="parameters"/>
  12. </message>
  13. <message name="printDataResponse">
  14. <part element="tns:printDataResponse" name="parameters"/>
  15. </message>
  16. <portType name="WebServiceDelegate">
  17. <operation name="printData">
  18. <input message="tns:printData"/>
  19. <output message="tns:printDataResponse"/>
  20. </operation>
  21. </portType>
  22. <binding name="WebServicePortBinding" type="tns:WebServiceDelegate">
  23. <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
  24. <operation name="printData">
  25. <soap:operation soapAction=""/>
  26. <input>
  27. <soap:body use="literal"/>
  28. </input>
  29. <output>
  30. <soap:body use="literal"/>
  31. </output>
  32. </operation>
  33. </binding>
  34. <service name="WebServiceService">
  35. <port binding="tns:WebServicePortBinding" name="WebServicePort">
  36. <soap:address location="http://localhost:8080/WebService/WebServicePort"/>
  37. </port>
  38. </service>
  39. </definitions>
  40. WebServiceService_schema1.xsd:用来说明Web Service的命令及其参数
  41. 比如:sample里面的WebService是【printData】,有一个String类型的参数【arg0】,返回值一个String类型的值。
  42. <?xml version="1.0" encoding="UTF-8"?>
  43. <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://webservice.com/" targetNamespace="http://webservice.com/" version="1.0">
  44. <xs:element name="printData" type="tns:printData"/>
  45. <xs:element name="printDataResponse" type="tns:printDataResponse"/>
  46. <xs:complexType name="printData">
  47. <xs:sequence>
  48. <xs:element minOccurs="0" name="arg0" type="xs:string"/>
  49. </xs:sequence>
  50. </xs:complexType>
  51. <xs:complexType name="printDataResponse">
  52. <xs:sequence>
  53. <xs:element minOccurs="0" name="return" type="xs:string"/>
  54. </xs:sequence>
  55. </xs:complexType>
  56. </xs:schema>
复制代码
 将WebService项目部署到Tomcat即可。
(部署方法略)
二. WSDL WebService的调用:
方法1:创建Web Service Client来调用:
1.创建【Java Project】:



image.png
2.点击工具栏的New Web Service Client:


image.png


image.png
3.选择【WSDL URL】:


image.png
4.点击【Next】完成创建后,在src/com/webservice下,自动天生相干文件。(WebServiceTest.java除外,这个是自己创建的调用文件)



image.png
5.创建【WebServiceTest.java】




image.png
代码如下:
package com.webservice;
public class WebServiceTest{
  1. public static void main(String[] args){
  2. WebServiceService wssPrintData = new WebServiceService();
  3. WebServiceDelegate wsdPrintData = wssPrintData.getWebServicePort();
  4. System.out.println(wsdPrintData.printData("sun"));
  5. }
复制代码
}
6.【WebServiceTest.java】右键→Run As→Java Application
输出结果:
Welcome to use WebService, sun


方法2:用HttpClient调用:
  1. package com.httpclientforwsdl;
  2. import java.io.ByteArrayInputStream;
  3. import java.io.InputStream;
  4. import java.util.HashMap;
  5. import java.util.Iterator;
  6. import java.util.Map;
  7. import org.apache.commons.httpclient.HttpClient;
  8. import org.apache.commons.httpclient.methods.InputStreamRequestEntity;
  9. import org.apache.commons.httpclient.methods.PostMethod;
  10. import org.apache.commons.httpclient.methods.RequestEntity;
  11. public class WebServiceHttpClientTest{
复制代码
  1. [/code] [code]
  2. public synchronized static String accessService(String wsdl,String ns,String method,Map<String,String> params,String result)throws Exception{
  3. //拼接参数
  4. String param = getParam(params);
  5. String soapResponseData = "";
  6. //拼接SOAP
  7. StringBuffer soapRequestData = new StringBuffer("");
  8. soapRequestData.append("<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">");
  9. soapRequestData.append("<soap:Body>");
  10. soapRequestData.append("<ns1:"+method+" xmlns:ns1=""+ns+"">");
  11. soapRequestData.append(param);
  12. soapRequestData.append("</ns1:"+method+">");
  13. soapRequestData.append("</soap:Body>" + "</soap:Envelope>");
  14. PostMethod postMethod = new PostMethod(wsdl);
  15. // 然后把Soap请求数据添加到PostMethod中
  16. byte[] b=null;
  17. InputStream is=null;
  18. try {
  19. b = soapRequestData.toString().getBytes("utf-8");
  20. is = new ByteArrayInputStream(b, 0, b.length);
  21. RequestEntity re = new InputStreamRequestEntity(is, b.length,"text/xml; charset=UTF-8");
  22. postMethod.setRequestEntity(re);
  23. HttpClient httpClient = new HttpClient();
  24. int status = httpClient.executeMethod(postMethod);
  25. System.out.println("status:"+status);
  26. if(status==200){
  27. soapResponseData = getMesage(postMethod.getResponseBodyAsString(),result);
  28. }
  29. } catch (Exception e) {
  30. e.printStackTrace();
  31. } finally{
  32. if(is!=null){
  33. is.close();
  34. }
  35. }
  36. return soapResponseData;
  37. }
  38. public static String getParam(Map<String,String> params){
  39. String param = "";
  40. if(params!=null){
  41. Iterator<String> it = params.keySet().iterator();
  42. while(it.hasNext()){
  43. String str = it.next();
  44. param+="<"+str+">";
  45. param+=params.get(str);
  46. param+="</"+str+">";
  47. }
  48. }
  49. return param;
  50. }
  51. public static String getMesage(String soapAttachment,String result){
  52. System.out.println("message:"+soapAttachment);
  53. if(result==null){
  54. return null;
  55. }
  56. if(soapAttachment!=null && soapAttachment.length()>0){
  57. int begin = soapAttachment.indexOf(result);
  58. begin = soapAttachment.indexOf(">", begin);
  59. int end = soapAttachment.indexOf("</"+result+">");
  60. String str = soapAttachment.substring(begin+1, end);
  61. str = str.replaceAll("<", "<");
  62. str = str.replaceAll(">", ">");
  63. return str;
  64. }else{
  65. return "";
  66. }
  67. }
  68. /**
  69. * @param args
  70. */
  71. public static void main(String[] args) {
  72. try {
  73. Map<String,String> param = new HashMap<String,String>();
  74. param.put("arg0", "sun");
  75. String wsdl="http://localhost:8080/WebService/WebServicePort?wsdl";
  76. String ns = "http://webservice.com/";
  77. String method="printData";
  78. String response =accessService(wsdl,ns,method,param,"return");
  79. System.out.println("main:"+response);
  80. } catch (Exception e) {
  81. e.printStackTrace();
  82. }
  83. }
复制代码
显示结果:
  1. status:200
  2. 七月 15, 2016 3:43:27 下午 org.apache.commons.httpclient.HttpMethodBase getResponseBody
  3. 警告: Going to buffer response body of large or unknown size. Using getResponseBodyAsStream instead is recommended.
  4. message:<?xml version="1.0" ?><S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"><S:Body><ns2:printDataResponse xmlns:ns2="http://webservice.com/"><return>Welcome to use WebService, sun</return></ns2:printDataResponse></S:Body></S:Envelope>
  5. main:Welcome to use WebService, sun
复制代码
【Dubbo 接口测试方法]

一.直接通telnet然后用dubbo协议调用方法

(1)在项目标配置文件中可以看到

dubbo.protocol.port=10022
说明dubbo对外暴漏的端口为10022,直接用telnet访问此端口。
telnet lcoalhost 10022然后就能看到


说明毗连成功。

  • 用ls查察服务


  • 查察服务下有那些方法ls -l



  • 然后利用invoke测试接口,这里留意,pom必要添加 fastjson的依赖不然报Invalid json argument, cause: com/alibaba/fastjson/JSON dubbo




二.Idea 插件dubbo Invoke

在idea插件超市中发现dubbo invoke 集成了invoke.

  • 下载安装插件DubboInvoke


  • 在对外暴漏的方法上加注释
  1. /**
  2. *
  3. * @param name 姓名
  4. * example=haha
  5. * @return
  6. */
  7. String sayHello(String name);
复制代码


  • 调用,点击这个接口出现的地方



选择利用插件,这里留意serverAddress为dubbo的服务ip 端口。



然后点击invoke,就能看到代测试结果。

四,【Http协议详解】

Http协议详解

思考:
用户打开一个浏览器,输入网址,向服务端发送数据,那么这个数据该如何发送呢?
若每个网站都有自己的规则,整个互联网就乱套了,而且用户访问也不是很方便,每个网站都要开发属于自己的客户端软件,致使运营成本变大。
以是,必须有一个同一的规则,让各人发送数据或接受数据有一个依据,于是,HTTP协议由此而来。
一、HTTP协议介绍

1.HTTP协议简介
HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于万维网(WWW:World Wide Web )服务器与当地浏览器之间传输超文本的传送协议。
HTTP是一个属于应用层的面向对象的协议,由于其简捷、快速的方式,适用于分布式超媒体信息体系。它于1990年提出,经过几年的利用与发展,得到不停地美满和扩展。HTTP协议工作于客户端-服务端架构为上。浏览器作为HTTP客户端通过URL向HTTP服务端即WEB服务器发送所有请求。Web服务器根据吸收到的请求后,向客户端发送响应信息。

利用HTTP协议,每当有新的请求发送时,就会有对应的新响应产 生。协议本身并不保存之前一切的请求或响应报文的信息。这是为了更快地处置处罚大量事件,确保协议的可伸缩性,而特意把HTTP协议计划成 云云简朴的。但是,随着Web的不停发展,因无状态而导致业务处置处罚变得棘手 的情况增多了。比如,用户登录到一家购物网站,纵然他跳转到该站的 其他页面后,也必要能继承保持登录状态。针对这个实例,网站为了能 够掌握是谁送出的请求,必要保存用户的状态。HTTP/1.1虽然是无状态协议,但为了实现渴望的保持状态功能, 于是引入了Cookie技能。有了Cookie再用HTTP协议通信,就可以管 理状态了。有关cookie的具体内容我们后面讲解。
2.什么是HTTP协议



  • 超文本传输协议, 规定了浏览器与服务端之间数据交互的格式
  • 将浏览器作为HTTP客户端通过URL向HTTP服务端即WEB服务器发送所有请求。
  • 如果服务端不遵循该协议,那就要自己开发一个客户端,让用户下载的的web应用,通过web应用访问,否则,用户通过浏览器是无法你的web应用的。
二、HTTP协议四大特性

1.基于TCP/IP协议之上的应用层协议

2.基于请求-响应模式

HTTP协议规定:请求从客户端发出,最后服务端响应客户端请求并返回
也是就说,用户访问数据先从客户端开始创建通信的,服务端在充公到请求之前不会发送数据并响应客户端。

3.无状态保存:不保存用户信息状态

HTTP是一种不保存状态,即无状态(stateless)协议。HTTP协议 自身不对请求和响应之间的通信状态进行保存。也就是说在HTTP这个级别,协议对于发送过的请求或响应都不做长期化处置处罚
总结:见你千百遍,我始终待你如初恋。

利用HTTP协议,每当有新的请求发送时,就会有对应的新响应产 生。协议本身并不保存之前一切的请求或响应报文的信息。
作用:


  • 为了更快地处置处罚大量事件,确保协议的可伸缩性,而特意把HTTP协议计划成 云云简朴的。
题目:


  • 随着Web的不停发展,因无状态而导致业务处置处罚变得棘手 的情况增多了
  • 比如,用户登录到一家购物网站,纵然他跳转到该站的 其他页面后,也必要能继承保持登录状态。针对这个实例,网站为了能 够掌握是谁送出的请求,必要保存用户的状态。那怎样实现
解决:


  • HTTP/1.1虽然是无状态协议,但为了实现渴望的保持状态功能, 于是引入了Cookie技能。
  • 有了Cookie再用HTTP协议通信,就可以管 理状态了。

4.无(短)毗连

无毗连的含义是限定每次毗连只处置处罚一个请求。服务器处置处罚完客户的请求,并收到客户的应答后,即断开毗连。即:客户端请求一次服务端就响应一次, 之后就没有任何关系。
作用:接纳这种方式可以节流传输时间。
解决方案:


  • 后面可以用websocket可以实现长毗连,可以让双方创建毗连后默认不停开毗连(QQ、微信聊天接纳的就是这种)
三、HTTP请求协议与响应协议

HTTP协议既然规定了客户端与服务端之间的通信格式,http协议包含由浏览器发送数据到服务器必要遵循的请求协议与服务器发送数据到浏览器必要遵循的请求协议。
那HTTP协议是怎么规定消息格式的呢?
首先我们来手撸一个socket服务端
简朴socket服务端:
  1. import socket
  2. server = socket.socket() # 默认就是基于网络的TCP协议
  3. server.bind(("127.0.0.1", 8888))
  4. server.listen(5)
  5. while True:
  6. conn, addr = server.accept()
  7. data = conn.recv(1024)
  8. print(data) # 将请求数据的打印出来
  9. conn.send(b"ok")
  10. conn.close()
复制代码
 然后将socket服务端运行起来看看,在浏览器URL输入:127.0.0.1:8888,socket服务端会受到如下数据:
  1. b'GET / HTTP/1.1\r\n ## 请求首行
  2. Host: 127.0.0.1:8080\r\n ## 请求头 (下面都是,一大堆的K:V键值对)
  3. Connection: keep-alive\r\n
  4. Cache-Control: max-age=0\r\n
  5. Upgrade-Insecure-Requests: 1\r\n
  6. User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3823.400 QQBrowser/10.7.4307.400\r\n
  7. Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8\r\n
  8. Accept-Encoding: gzip, deflate, br\r\n
  9. Accept-Language: zh-CN,zh;q=0.9\r\n
  10. Cookie: csrftoken=WCzjKvmjOSdJbYKs0uIfPtiFfLl04FENb6p9CjypP7ZObcUpydaQPLZN0qPOVqwj\r\n
  11. \r\n' ## 换行
  12. b'' ## 请求体
复制代码



  • 用于HTTP协议交互的信被为HTTP报文。请求端(客户端)的HTTP报文 做请求报文,响应端(服务器端)的 做响应报文。
  • HTTP报文本身是由多行数据构成的字文本

然后我们再来访问一下CSDN, 查察浏览器收到的相应数据 : 在网页中鼠标右击检查---->Network---->点击当前网页的网址---->Headers----->查察 Response Headers

1.请求协议

1.1 请求格式



HTTP GET方法的请求格式


  • 格式说明:
  1. // 请求首行 : 请求方法, 协议版本...
  2. // 请求头 : 一大堆的 k:v 键值对
  3. // 空行 \r\n : 用来标识作用
  4. // 请求体 : 并不是所有的请求方法都有, 只要用来携带敏感性数据(get没有,post有)
复制代码







  • 请求方式:

    • "get" 请求 : 朝服务端索要数据 (例 : 输入网址获取对应的内容)
    • "post" 请求 : 朝服务端提交数据 (例 : 登入,输入用户名密码,提交到服务端进行校验)

  • get 与 post 的区别
    1. 1. 都可以携带额外的参数 :
    2. // GET 提交的数据会放在URL之后,以"?"分割URL和传输数据,参数之间以"&"相连
    3. // POST方法是把提交的数据放在HTTP包的请求体(Body)中.
    4. 2. 提交的数据大小限制 :
    5. // 浏览器对URL长度有限制, 所以GET提交的数据大小有限制
    6. // POST方法没有数据大小限制
    7. 3. 数据的安全性 :
    8. // GET方式提交数据, 会带来安全问题, 比如一个登录页面, 通过GET方式提交数据时, 用户名和密码将出现在URL上
    9. // 如果页面可以被缓存或者其他人可以访问这台机器, 就可以从历史记录获得该用户的账号和密码
    复制代码

2.HTTP响应

服务器收到了客户端发来的HTTP请求后,根据HTTP请求中的动作要求,服务端做出具体的动作,将结果回应给客户端,称为HTTP响应。
2.1 请求格式


格式说明
  1. // 响应首行 : 响应状态码, 协议版本....
  2. // 响应头 : 一大堆 k:v 键值对
  3. // 空行 \r\n : 用来标识作用
  4. // 响应体 : 响应正文, 展示给用户的数据
复制代码



  • HTTP响应由三部分组成:状态行、响应头、响应正文;
  • 状态行:包括协议版本Version、状态码Status Code、回应短语;
  • 响应头(server header):包括搭建服务器的软件,发送响应的时间,回应数据的格式等信息,包含HTTP状态码 (HTTP Status Code) ;
  • 响应正文:就是响应的具体数据。
响应状态码说明:
HTTP状态码由三个十进制数字组成,第一个十进制数字界说了状态码的范例,后两个数字有分类的作用。不同的状态码代表不同的含义。

  1. [/code] [list=1]
  2. [*] // 用简朴的数字来表示一串中文意思(状态或者描述性信息)
  3. [*] 1XX : 1开头的,服务端已经接受到你的数据正在处置处罚,你可以继承提交
  4. [*] 2XX : 200 OK>>> : 请求成功
  5. [*] 3XX : 重定向(当你在访问一个必要登陆之后才能看的页面你会发现会自动跳转到登陆页面)
  6. [*] 4XX : 403当前请求不符合条件(没有权限), 404请求资源不存在
  7. [*] 5XX : 服务器内部错误,无法完成请求
  8. [/list]  ps : 除了上面提到的响应码之外, 公司内部还会自界说自己的状态码
  9. [size=3]四、URL 同一资源定位符[/size]
  10. 同一资源定位符是对可以从互联网上得到的资源的位置和访问方法的一种简洁的表示,是互联网上标准资源的地点。互联网上的每个文件都有一个唯一的URL,它包含的信息指出文件的位置以及浏览器应该怎么处置处罚它
  11. 格式:
  12. 协议://IP:端口(80)/路径?name=lqz&age=18
  13. ?之前的是请求路径,?之后的是请求数据部分
  14. 情势 : scheme:[//[user:password@]host[:port]][/]path[?query-string][#anchor]
  15.  提示 : 方框内的是可选部分
  16. [list]
  17. [*] scheme :协议(比方:http, https, ftp)
  18. [*]user : password@用户的登录名以及密码
  19. [*]host :服务器的IP地点或者域名
  20. [*]port :服务器的端口(如果是走协议默认端口,http 80 or https 443)
  21. [*]path :访问资源的路径
  22. [*]query-string :参数,它通常利用键值对来制定发送给http服务器的数据
  23. [*]anchor :锚(跳转到网页的指定锚点位置)
  24. [/list] [size=4]编写接口测试计划[/size]
  25. 接口测试计划和功能测试计划的目标划一,都是为了确定需求、确定测试情况及测试方法,为计划测试用列做准备,开端制定接口测试进度方案。一般来说,接口测试计划包含概述、测试资源、测试功能及重点、测试计谋、测试风险、测试标准。
  26. [size=4]编写、评审接口测试用例[/size]
  27. 和功能测试雷同,在开始接口测试前,必要根据球必要文档、接口文档等项目相干文档编写并评审接口测试用例,接口思绪如图所示:
  28. [align=center][img]https://i-blog.csdnimg.cn/blog_migrate/cac9d9fad4b341254d62fe60c1c99b52.png[/img][/align]
  29. [size=4]执行接口测试[/size]
  30. 依据编写的接口测试用例,借助测试工具(如Postman、JMeter、SoapUI)执行接口测试,上报发现题目。
  31. [size=2]接口自动化持续集成要点[/size]
  32. 进行项目测试时,接口会曾加、淘汰或变更,测试用例也会相应的更新,因此必要借助工具(如GitHub等)来维护测试用例进行持续集成,通过自动化测试及时监控项目接口运行情况。对接口测试而言,持续集成是核心内容,通过自动化的手段才能做到低成本、高收益。接口自动化测试持续集成重要包括以下内容:
  33. (1)流程方面:在回归阶段加强接口异常场景的覆盖,并逐步向体系测试、冒烟测试阶段延伸,终极到达全流程自动化。
  34. (2)结果展示:更加丰富的结果展示、趋势分析、质量统计和分析等。
  35. (3)题目定位:报错信息、日志更精准,方便题目复现与定位。
  36. (4)结果校验:加强自动化校验能力,如数据库信息校验。
  37. (5)代码覆盖率:不停实验由现在的黑盒向白盒下探,提高代码覆盖率。
  38. (6)性能需求:美满性能测试体系,通过自动化的手段监控接口性能指标是否正常。
  39.  -----------------------
  40. 接口测试流程及用例计划
  41. 接口测试是整项目测试过程中非常重要的一环,测试的对象是接口,以是可以很早的介入测试,对代码逻辑进行全面验证,更早的发现步调的题目,比UI测试服从更高,并且更轻易验证极端和异常的情况。
  42. [size=2]接口测试流程:[/size]
  43. 雷同于功能测试流程,一个完整的接口测试流程如下:
  44. [list=1]
  45. [*]分析接口文档和需求文档
  46. [*]编写接口测试计划
  47. [*]编写接口测试用例
  48. [*]接口测试执行
  49. [*]输出接口测试陈诉。
  50. [/list] 一般接口用例计划依据的就是开发提供的接口文档和产物需求文档,首先熟悉一下接口文档。
  51. [size=2]接口文档[/size]
  52. 接口文档如何描述一个具体的接口信息,示比方下:[align=center][img=624,475]https://i-blog.csdnimg.cn/blog_migrate/6cf59754670adc86f150213cd8a42767.png[/img][/align]
  53. 接口文档
  54. [size=2]重要包括如下几个部分:[/size]
  55. [list]
  56. [*]接口说明
  57. [*]请求方式
  58. [*]请求URL
  59. [*]请求参数
  60. [*]返回数据
  61. [*]返回实例
  62. [/list]
  63. [size=2]接口用例计划原则[/size]
  64. 接口测试的原理就是模仿客户端向服务器发送请求报文,服务器吸收请求报文后对相应的报文做处置处罚并向客户端返回应答,客户端吸收应答的过程。
  65. 接口测试接纳的方法着实与黑盒测试划一的,甚至可以把接口测试理解为没有界面的功能测试。只不过接口测试的测试点更多一些,除了界面上必要验证的各种功能点,还包括接口的安全、接口的性能等。
  66. 一般测试用例的计划要从单接口参数的校验到整个业务功能点的验证,还可以验证一些安全性和异常情况。
  67. 接口用例计划点基本原则如下:
  68.  [align=center][img=643,450]https://i-blog.csdnimg.cn/blog_migrate/c832d2b4683a726e9b362a6bfb98d08f.png[/img][/align]
  69. 接口测试用例计划原则 
  70. [size=2]怎么确定用例的覆盖率?[/size]
  71. 如何快速评估自己的测试用例覆盖率: 1)参数验证是否完整(包括各种界限和业务规则) 2)业务需求点覆盖是否完整(单接口业务功,依赖接口业务功能) 3)接口异常场景覆盖是否完整(数据的异常,)
  72. [size=2]一般接口用例要包含如下部分:[/size]
  73. 用例编号、模块名称、接口名称、用例标题、请求方法、请求URL、请求参数(包括请求头、请求体)、预期结果、现实结果等。
  74. 不肯定都必要有,根据现实利用增减,一个现实的用例模板如下:[align=center][img=648,265]https://i-blog.csdnimg.cn/blog_migrate/f08d32dfa1ba8877a6843e5ef5d0ae72.png[/img][/align]
  75. 接口测试用例
  76. ------------
  77. 一、接口用例模板
  78. 提到测试用例,我们知道,其中最重要的两个要素就是:测试步调和预期结果。着实对于接口测试也同样云云,接口测试的步调中,最重要的是将实现向接口发送预设请求,结果则要关注响应信息及后续处置处罚。以是接口测试用例编排可以考虑下列两种情势。要留意的是,现实工作场景中我们大概还会对接口之间的串联和混淆场景进行测试。
  79. [align=center][img]https://i-blog.csdnimg.cn/blog_migrate/09284b72c3a55a337c96230bfcc40952.jpeg[/img][/align]
  80. [align=center][img]https://i-blog.csdnimg.cn/blog_migrate/be62fd2d5140b77f6b6b6b9b1b4bd2be.jpeg[/img][/align]
  81. 二、测试陈诉模板
  82. 接口测试陈诉很多时间会和接口性能测试陈诉一起,如果要单独陈诉的话,可以考虑以下内容:
  83. [align=center][img]https://i-blog.csdnimg.cn/blog_migrate/a289a0288aa3d526650ebd89632bb168.jpeg[/img][/align]
  84. 简要描述与测试项目相干的一些背景资料,如被测体系简介,项目上线计划等。对于体系接口的界说和计划做出介绍。比如体系一共有多少个接口?接纳哪种协议?都涉及到哪些发送方法?接纳怎样的请求格式?利用怎样的返回标准?可用表格说明。而描述本次接口测试的目标、范围与目标,内容应与本次接口测试的《接口测试实行方案》中的对应内容保持划一。
  85. 测试目标在于确保体系接口功能和逻辑处置处罚已验证,符合《接口界说说明书》的界说和要求,满足体系必要。测试对象重要分为单场景接口功能测试和混淆场景接口功能测试。这点可以从《项目接口测试用例》可考虑贴出x-mind图。
  86. 其中测试指标范围重要分为被测接口吸收请求和返回报文,被测接口返回状态,被测接口对应业务逻辑处置处罚,涉及数据沉淀的处置处罚,复杂场景下多接口串联交互。然后测试工具将利用Postman,而Postman是谷歌的一款接口测试插件,它利用简朴,支持用例管理,支持get、 post、文件上传、响应验证、变量管理、情况参数管理等功能,可以批量运 行,并支持用例导出、导入。
  87. [align=center][img]https://i-blog.csdnimg.cn/blog_migrate/47d23792ee5c8c32be323da006861fde.jpeg[/img][/align]
  88. 测试资源
  89. 测试记录可以分为单场景接口测试和测试结果数据。然后结合测试中发现的题目对于团体测试结果进行分析,做出判断。而这些题目就包括接口业务功能错误类缺陷情况,接口异常处置处罚类缺陷情况,接口处置处罚数据沉淀缺陷类情况和接口安全性缺陷情况。
  90. [align=center][img]https://i-blog.csdnimg.cn/blog_migrate/795e92bc2764f836d073cdaeb8d349cc.jpeg[/img][/align]
  91. 而混淆场景接口测试中就包括测试结果数据和本次混淆场景接口测试的测试结果数据。
  92. [align=center][img]https://i-blog.csdnimg.cn/blog_migrate/9efb7d6f185daf032b8dbd440f83f9fd.jpeg[/img][/align]
  93. 之后结合测试中发现的题目对于团体测试结果进行分析,做出判断,就能得出本次性能测试的测试总结论,一般以测试结果与测试目标的比较结果作为测试结论。
  94. ------
  95. 1 项目地点
  96.     https://gitee.com/HUJIAFANGFUJIDDD/vue_api_server.git
  97. 2 部署
  98.   #cd /usr/local
  99. #git clone https://gitee.com/HUJIAFANGFUJIDDD/vue_api_server.git     (如没有安装git 先 yum install git -y)3 安装npm和node情况
  100. [code]
  101. wget https://npm.taobao.org/mirrors/node/v14.15.3/node-v14.15.3-linux-x64.tar.xz
  102. xz -d node-v14.15.3-linux-x64.tar.xz
  103. tar -xvf node-v14.15.3-linux-x64.tar
  104. cd node-v14.15.3-linux-x64
  105. # 建立软连接,变为全局
  106. ln -s /usr/local/nodejs/node-v14.15.3-linux-x64/bin/npm /usr/local/bin/
  107. ln -s /usr/local/nodejs/node-v14.15.3-linux-x64/bin/node /usr/local/bin/
  108. vim /etc/profile
  109. # 以下两个路径为加入nodejs路径
  110. export NODE_HOME=/usr/local/nodejs/node-v14.15.3-linux-x64
  111. export PATH=$NODE_HOME/bin:$PATH
  112. # 配置生效
  113. source /etc/profile
  114. # 成功
  115. node -v
复制代码
4 进入到vue_api_server项目目录,接着执行npm install 安装依赖包。
5 安装Mysql,如果你已经有的话,可以直接忽略此步
6 进入db目录中,将mydb.sql导入到Mysql数据库中
  mysql>CREATE DATABASE `api_db_mysql` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
 mysql>use api_db_mysql;
  mysql>source /usr/local/vue_api_server/db/mydb.sql
7 进入到vue_api_server目录下的config目录中,打开文件default.json    修改后如下:
  1. {
  2. "config_name" : "develop",
  3. "jwt_config" : {
  4. "secretKey":"itcast",
  5. "expiresIn":86400
  6. },
  7. "upload_config":{
  8. "baseURL":"http://192.168.234.133:8888",
  9. "upload_ueditor":"uploads/ueditor",
  10. "simple_upload_redirect":"http://192.168.234.133/reload"
  11. },
  12. "db_config" : {
  13. "protocol" : "mysql",
  14. "host" : "127.0.0.1",
  15. "database" : "api_db_mysql",
  16. "user" : "root",
  17. "password" : "Xsy@210721",
  18. "port" : 3306
  19. }
  20. }
复制代码
8 在vue_api_server目录下, 执行命令
#node app.js
返回这些log表示部署成功:

9 利用VUE_API_Server
完成前面的服务情况部署后,默认后监听8888服务端口,接口基准地点http://192.168.234.133:8888/api/private/v1/,且数据返回格式同一利用 JSON。

登录接口:


获取roles接口 (留意在Authorization中添加Type=Bearer Token, Token值就是上面登录接口返回的那个token值)


留意:
创建用户,查询用户这类的业务接口,必要从登录授权的 API 中获取到token,且必须在请求头中利用 Authorization 字段提供 token 令牌
项目中有很多接口,执行node app.js 会打印出所有的接口

【接口测试工具详解】
接口测试工具

  接口测试工具如图:


1.Fiddler
首先,这是一个HTTP协议调试代理工具,说白了就是一个抓http包的工具。web测试和手机测试都能用到这个工具。既然是http协议,这个工具也能支持接口测试。稍后文章,我会专门介绍fiddler这个工具。
2.PostMan
Postman一款非常盛行的API调试工具。着实,开发人员用的更多。因为测试人员做接口测试会有更多选择,比方Jmeter、soapUI等。不过,对于开发过程中去调试接口,Postman确实充足的简朴方便,而且功能强盛。这是一款google工
程师开发的一个插件,可以安装到chrome浏览器上。支持不同接口测试请求,能够管理测试套件和自动化运行,弱点在于,自动化断言功能不强盛。不能和jenkins和代码管理库进行持续集成测试。但是,绝对是一个很好的半手工,半自动化测
试工具,我一般在写自动化接口测试用例,会打开postman进行辅助测试和debug。这个工具也会稍后在文章介绍。
 这个是一款计算机上抓包工具,支持抓各种包,TCP,UDP,HTTP都支持。如果做底层网络数据测试,一般都必要用到它。作为接口测试,这个软件有点不友好。因为刷新数据太快,欠好定位每个操作对应的接口。以是,我们不会进行过多
介绍这个工具。
4.SoupUI    
SoapUI是一个开源测试工具,通过soap/http来检查、调用、实现Web Service的功能/负载/符合性测试。该工具既可作为一个单独的测试软件利用,也可利用插件集成到Eclipse,maven2.X,Netbeans 和intellij中利用。
SoapUI是一个自由和开放源码的跨平台功能测试解决方案。通过一个易于利用的图形界面和企业级功能,SoapUI让您轻松, 快速创建和执行自动化功能、回归、合规和负载测试。在一个测试情况,SoapUI提供完整的测试覆盖,并支持所
有的标准协媾和技能。
SoapUI 基于Java 开发,支持多个平台,安装非常简朴。
这个是一个开源免费和,企业版收费的软件。在国外的接口测试,利用非常多。这个工具能够支持接口自动化测试和接口性能测试,也能支持和jenkins做持续集成测试。了解一下就可以,自己可以下载一个社区免费版,做一个demo试试。
5.Java代码做接口测试
代码是万能,笔记工具也是代码开发出来的。为什么要用代码做接口自动化测试呢。因为,有些工具功能是有限定,很多公司,必要一些特定的功能,工具不支持,只好用代码进行开发。一般用Java做自动化测试,重要是利用httpclient.jar
这个包,然后利用junit或者testng这样的单位测试工具,进行测试用例的开发,然后在jenkins上创建一个job,进行持续集成测试。
6.Python代码做接口测试
      和Java一样,Python中利用一个很好,功能强盛的第三方库requests,能够方便都创建接口自动化用例。python下单位测试框架,一般接纳unittest。天生测试陈诉,一般选择HTMLTestRunner.py。同样,可以和jenkins做持续集成测试。
7.LoadRunner
       不要以为LR只能做性能测试,loadrunner同样可以做接口自动化和接口压力测试。只是我们很多人,不会利用LR的函数,进行开发接口测试用例。
8.JMeter
      JMeter同loadrunner一样,都是以性能测试着名,一般用JMeter也是做接口性能测试。比方java+Jmeter+ant+jenkins做接口性能监听测试。
      以上介绍了这么多工具,基本覆盖了接口功能测试,接口自动化测试,接口性能测试。
 
五,【深入了解cookie,session,token鉴权原理以及实战】-------

cookie

cookie是保存在客户端的一段小文本,可以用来标识用户身份,它会在浏览器下次向同一服务器再发起请求时被携带并发送到服务器上。
优点:


  • 通过cookie可以让服务器以较小成本标识用户会话。
  • cookie只会发往设置该cookie的域名,这保证了cookie的相对安全。
  • 由于cookie没有遵循严格的同源计谋,以是一个子域可以设置获取父域的cookie,这种特性十分有利于实现单点登录。
  • 可以设置cookie过期时间,从而保证cookie在有效期内利用。
 缺点:


  • cookie巨细只有4k,因此不能保存大量内容。
  • cookie保存在客户端,因此不敷安全,如果有人挟制了cookie,服务器无法区分出来是用户本人照旧hacker在利用会话状态。
  • 服务器端如果没有设置克制js读取cookie的话,js是可以创建修改删除该域名下的cookie的,因此为了防止xss攻击,必要将cookie设置为HttpOnly。
  • 如果浏览器设置了禁用cookie,则服务器无法根据cookie追踪用户会话
 伪代码
  1. [/code] [code]
  2. @GetMapping("put")
  3. public void test2(HttpServletRequest request, HttpServletResponse response){
  4. // Cookie 为键值对数据格式
  5. Cookie cookie_username = new Cookie("cookie_username", "admin");
  6. // 即:过期时间,单位是:秒(s)
  7. cookie_username.setMaxAge(30 * 24 * 60 * 60);
  8. // 表示当前项目下都携带这个cookie
  9. cookie_username.setPath(request.getContextPath());
  10. // 使用 HttpServletResponse 对象向客户端发送 Cookie
  11. response.addCookie(cookie_username);
  12. }
  13. @GetMapping("del")
  14. public void test4(HttpServletRequest request, HttpServletResponse response){
  15. // 根据 key 将 value 置空
  16. Cookie cookie_username = new Cookie("cookie_username", "");
  17. // 设置持久时间为0
  18. cookie_username.setMaxAge(0);
  19. // 设置共享路径
  20. cookie_username.setPath(request.getContextPath());
  21. // 向客户端发送 Cookie
  22. response.addCookie(cookie_username);
  23. }
复制代码
执行put请求之后,可以在客户端看到:


执行del请求之后,在客户端是看不到的:

session
session是存储在服务器,用来标识用户会话的另一种机制,基于cookie实现的。用户发起请求后,服务器会针对该请求创建一个session并可以设置相干属性,然后服务器将sessionid放入cookie中返回给浏览器。浏览器以后请求都带上这个cookie,服务器通过sessionid就可以拿到相应的session并知道这是哪个用户的会话了。
原理图:


优点:


  • 将用户信息保存在服务器,安全性较好
  • 即利用户禁用cookie,仍然可以用拼接在url后边的方式来传递sessionid
  • 可以设置失效时间,有续约机制可以让会话时间更长
  • 利用session可以使页面间传参更加方便
缺点:


  • 会加剧服务器存储负担,如果将session放到内存中,则大用户量的情况下对内存也是一个挑战
  • 如果是分布式服务器,不能很好的同步session信息
伪代码

  1. @GetMapping("put")
  2. public void test4( HttpSession session){
  3. session.setAttribute("session_username","admin");
  4. }
  5. @GetMapping("del")
  6. public void test5(HttpSession session){
  7. session.removeAttribute("session_username");
  8. }
  9. @GetMapping("get")
  10. public void test6( HttpSession session){
  11. System.out.println(session.getAttribute("session_username"));
  12. }
  13. // 常用方法
  14. // public Object getAttribute(String name)
  15. // 返回session对象中与指定名称绑定的对象,如果不存在则返回null
  16. //
  17. // public Enumeration getAttributeNames()
  18. // 返回session对象中所有的对象名称
  19. //
  20. // public long getCreationTime()
  21. // 返回session对象被创建的时间, 以毫秒为单位,从1970年1月1号凌晨开始算起
  22. //
  23. // public String getId()
  24. // 返回session对象的ID
  25. //
  26. // public long getLastAccessedTime()
  27. // 返回客户端最后访问的时间,以毫秒为单位,从1970年1月1号凌晨开始算起
  28. //
  29. // public int getMaxInactiveInterval()
  30. // 返回最大时间间隔,以秒为单位,servlet 容器将会在这段时间内保持会话打开
  31. //
  32. // public void invalidate()
  33. // 将session无效化,解绑任何与该session绑定的对象
  34. //
  35. // public boolean isNew()
  36. // 返回是否为一个新的客户端,或者客户端是否拒绝加入session
  37. //
  38. // public void removeAttribute(String name)
  39. // 移除session中指定名称的对象
  40. //
  41. // public void setAttribute(String name, Object value)
  42. // 使用指定的名称和值来产生一个对象并绑定到session中
  43. //
  44. // public void setMaxInactiveInterval(int interval)
  45. // 用来指定时间,以秒为单位,servlet容器将会在这段时间内保持会话有
复制代码
执行put请求后,在客户端是看不到的 
执行get请求,可以在服务端看到
执行del请求后再执行get请求,不可以在服务端看到
   有关分布式session题目,可查察分布式session共享题目 
  token
token是一种身份验证方法,被很多人翻译过来后生动的称为“令牌”,它的扩展性,安全性更高,非常适合用在Web应用和移动开发应用上。
Token有很多种,比如常用的jwt,全称是 Json Web Token, 是JSON风格轻量级的授权和身份认证规范,可实现无状态、 分布式的 Web 应用授权。
区别:


  • 普通令牌:服务端验证客户端发送的token信息必要进行数据的查询操作
  • jwt令牌:jwt令牌中本身存储着用户信息,可直接从jwt令牌中剖析出用户信息
最后感谢每一个认真阅读我文章的人,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走:


这些资料,对于【软件测试】的朋侪来说应该是最全面最完整的备战堆栈,这个堆栈也伴随上万个测试工程师们走过最艰巨的路程,盼望也能帮助到你!


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

杀鸡焉用牛刀

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表