看完这篇博客,我保证你确定会作接口测试了。

最近给公司的新员工培训web api接口测试,发现这一块的内部需求还比较大,不只仅是新员工,包括一些常常写接口测试老员工,对接口也是似懂非懂的,因此我绝对有必要写一篇博客来普及下。css

在咱们公司内部,通常使用ruby或者python语言来作接口测试,这篇文件主要是讲解使用python语言来作接口测试。html

若是要作接口测试,其实只要会抓包会组装http请求头和请求体会检查http响应头和响应体,就能够能够,因此咱们须要须要掌握下面这些知识!!!另外还须要掌握一些经常使用的测试框架,好比unittest和pytest等python

一、python语言requests库web

二、http协议基本知识,包括请求头,响应头、请求体、响应体数据库

三、session-cookie(若是你们对session和cookies不熟悉,能够看我以前写 的博客)json

https://www.cnblogs.com/bainianminguo/p/9147418.html后端

https://www.cnblogs.com/bainianminguo/p/8850043.htmlapi

四、fiddler抓包工具浏览器

五、测试框架,这里不会讲,你们有兴趣能够看下我以前写的博客,介绍unittest测试框架ruby

https://www.cnblogs.com/bainianminguo/p/11706244.html

https://www.cnblogs.com/bainianminguo/p/11616526.html

 

下面进入正题,听我娓娓道来。

1、http协议

一、简介

web api接口大都是基于http协议的,因此要进行接口测试,首先要了解HTTP协议的基础知识。

HTTP协议全称是超文本传输协议。因为HTTP最初是用来在浏览器和网站服务器之间传输超文本的(网页,视频,图片等)信息的。因为HTTP简洁易用,后来,不只仅是浏览器和服务器之间使用它,服务器和服务器之间,手机app和服务器之间,都普遍的采用,成了一个软件系统间通讯的首选协议之一。

HTTP协议有好几个版本,包括0.九、1.0、1.一、1.2,当前最普遍使用的是HTTP/1.1版本

HTTP协议最大的特色是通信双方分为客户端和服务端。

因为目前HTTP是基于TCP协议,因此要进行通信,客户端必须先河服务端建立TCP链接。并且HTTP双方的信息交互,必需要这样一种形式

a、客户端先发送http请求(request)给服务器

b、而后服务器发送http响应(response)给客户端

c、特别要注意,在http协议中,服务端是不能主动发消息给客户端的

流程图以下

 

 

 

http1.1版本先建立TCP链接,而后在这个链接内能够进行屡次交互信息,这里注意,是客户端主动给服务端发请求的

 

2、http请求

下面是http的get请求和http的post请求的示例

GET /mgr/login HTTP/1.1
Host: 192.168.3.1
User-Agent:Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36
Accept-Language:zh-CN,zh;q=0.8,en-US;q=0.6,en;q=0.4
Accept-Encoding:gzip, deflate, sdch

  

POST /api/test HTTP/1.1
Host:192.168.3.1
Origin:http://192.168.3.1
Referer:http://192.168.3.1/html/index.html
User-Agent:Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36
Content-Type:application/json;charset=UTF-8
Content-Length:214
Accept-Language:zh-CN,zh;q=0.8,en-US;q=0.6,en;q=0.4
Accept-Encoding:gzip, deflate

{"csrf":{"csrf_param":"35iUJau6mdmmJeIg0N8W80OmoMK8A2Kr","csrf_token":"KfKSfpH0hnsSc0uQyX6ZUB8i8KRFSZ0C"},"data":{"username":"admin","firstnonce":"c7eb46830667147fc62838e7ba9a0c09187d28bafa45b133897efa9d4e46a880"}}

  

一个http请求消息由下面几个部分组成

a、请求行 request line

是http的第一行的内容。表示要操做什么资源,使用的http协议的版本是什么,里面包含了三部分消息。请求的方法、操做资源的地址、协议的版本号

 

b、请求方法

Get请求

从服务器上获取资源信息,这是一种最多见的请求

好比要从服务器获取网页资源,获取图片资源,获取用户信息数据等

 

Post请求

添加资源信息到服务器进行处理,例如要添加用户信息,上传图片数据到服务器等,具体的数据信息,一般在HTTP请求的消息体中,这个后面会讲

 

 Put请求

请求服务器更新资源信息

好比要更新用户、姓名地址等等

具体的更新的数据信息,一般在HTTP的消息体中,后面会讲

 

Delete请求

请求服务器删除资源信息

好比要删除某个用户,某个资源等等

HTT片协议还有许多其余的方法,好比PATCH,HEAD等,不是特别经常使用,暂且不讲

 

c、资源地址

 

 

 

d、请求头

 

 

 

这里业务你们有个疑问,个人http请求是创建在tcp链接的基础上的,为何这里还要传递一个host呢?由于咱们知道ip地址了,可是这个ip地址上可能有多个网站,因此这里要指定咱们要访问的具体是哪一个网站

请求体的http请求下面的内容,里面存放一些信息。

好比请求发送的服务端的域名是什么,但愿接受的响应消息使用语言,请求消息体的长度等等;

一般请求头有好多个,一个请求头占据一行

单个请求头的格式是:名字:值

 

e、请求体

请求的url,请求头中可存放一些数据信息,可是有些数据信息,每每需求存放在消息体中国;特别是post,put的请求,添加,修改的数据信息一般都是存放在请求消息体中的;

若是HTTP请求有消息体,协议规定,须要在消息头和消息体之间插入一个空行,隔开他们;

请求消息体中保存了要提交个服务端的数据信息

好比:客户端要上传一个文件给服务器,就能够经过http请求发送文件数据给服务端;

文件的数据就应该在请求的消息体中

请求的消息体一般是某种格式的字符串,常见的有三种,可是最经常使用的仍是json格式

Json

Xml

www-form-urlencoded

后面会有详细的描述

 

request payload就是一个请求体,下面这个格式就是Json格式的消息体

 

 

 

请求体中不只仅能够存放字符串,还能够放二进制信息,好比如下视频、文本之类的,用于咱们上传文件的场景,不过一般接口测试不会涉及二进制信息,都是字符串信息,后面我会专门写一篇博客来介绍如何上传文件

 

二、http响应

响应的消息咱们重点关注状态码

a、2xx

一般表示请求消息没有问题,并且服务器也正确处理了

b、3xx

这是重定向响应,常见的是是30一、302,表示客户端的这个请求的url地址已经改变了,须要客户端重启发起一个请求到另一个url

c、400

表示客户端请求不符合接口要求,好比格式彻底错误

d、401

表示客户端须要先认证才能发送请求

e、403

表示客户端美誉哦权限要求服务器处理这样的请求,好比普通用户的没有管理员的权限

f、404

表示客户端方法的url不存在

g、5xx

表示服务端在处理请求中,发送了未知错误,一般是服务端的代码设计的问题,或者服务端系统出了故障了

 

有了以上的基础,咱们就能够作web的接口测试了

2、接口测试

一、什么是接口测试

咱们一般说的接口测试,其实就是对软件系统的消息交互接口的参数,消息交互接口是软件系统和其余软件系统交互的那部分,好比,你正在用浏览器使用一个网站,浏览器和后端服务器之间就是消息交互的;在好比,你手机上使用美团订餐,美团app和美团服务器之间,也是消息交互的,当你提交订单,使用功能微信支付的时候,美团服务器和微信服务器之间也是经过消息交互的

 

 

 

 

接口测试就是

依据接口规范,写出测试用例

使用软件工具,直接经过消息接口对被测系统进行消息收发

验证被测系统行为是否正确

 

目前软件系统之间的消息接口大部分是基于HTTP协议收发的

HTTP协议的特色是,客户端发出一个HTTP请求给服务端,服务端就返回一个HTTP相应,好像API程序调用;

全部接口测试一般又被称为API接口测试或者WEB API接口测试

 

API接口传递数据信息是经过HTTP协议进行收发的,网站获取网页,图片,css等资源,也是经过HTTP协议进行收发的

那么这二者有什么区别呢?为何获取网页,图片这些HTTP消息不叫作API接口消息呢?

网页,图片,css这些资源都是静态资源,就是一个一个文件存储在服务器中,获取这些消息,服务端直接读取文件,返回给客户端便可,无需特别的数据处理

 

而API接口请求消息,一般都须要服务端程序进行一番处理,好比对请求的权限检查,从数据库中读出数据,进行消息过滤和格式转换,最后在HTTP响应中返回给客户端

接口测试须要工具和被测系统之间进行消息的收发,这个工具能够是别人开发的,也能够本身开发,基于HTTP的接口测试工具备Postman,Jmeter等

 

二、fiddler工具

这里咱们使用python语言中的requests库和fiddler抓包工具

Fiddler:代理式抓包

你们必定会反问,个人浏览器就是能够抓包了,为何还要安装fiddler,画蛇添足?

其实否则,由于咱们是用python的requests库去作接口测试,浏览器是抓不到咱们发的请求的,因此须要安装fiddler来抓包,确保咱们发送的http请求是正确的

 

fiddler启动后,会启动一个代理服务器,监听在8888端口上,http客户端须要设置fiddler做为代理,把http请求消息发送给fiddler,fiddler转发http消息给服务端,服务端返回消息也是先返回给fiddler。再由fidddler转发给客户端

以下图所示

 

 

  

fiddler安装后,会默认配置操做系统级别的代理,能够经过下面的方式查看

 

 

 

安装fiddler须要配置一个过滤项,由于默认fiddler是做为一个系统代理,因此fiddler抓到包会不少,因此须要配置一个过滤项

 

 

 

 

一样,这里的配置是支持通配符的

 

 

 

抓包

 

 

 

 

查看原始的请求消息

 

 

 

 

咱们能够在python代码里配置代理,而后经过fiddler抓包来判断咱们发的包是否准确,这里须要配置http和https协议的代理

import requests

proxies = {
    "http":"127.0.0.1:8888",
    "http1": "127.0.0.1:8888"
}

res = requests.get(
    url = "htt://www.baidu.com",
    proxies = proxies
)

  

咱们能够经过fiddler进行抓包

 

 

 

fiddler若是 要配置手机抓包代理,须要保证安装fiddler和手机在同一个局域网中

 

 

 

在手机的无线网络处配置代理,代理指向运行fiddler的电脑的ip便可,端口是8888

 

三、requests库的请求

a、构建请求的url参数,这个通常在get请求使用较多

什么是url参数

好比

https://www.baidu.com/s?wd=iphone&res_spt=1

  

问号后面的部分wd=iphone&res_spt=1就是url参数,每一个参数之间就用&隔开的。

上面的例子中有两个参数wd和res_spt,他们的值分别iphone和1

url参数参数的格式,有个术语叫urlencoded格式

 

使用requests发送HTTP请求,url里面的参数,一般能够直接在url里面,好比

 

 

可是有的时候,咱们的url中参数里面有特殊字符,好比参数中的值包含了一个&这个符号或者参数不少的话,咱们能够采用下面的方法,构建一个字典,而后把这个字典传递给params参数 

也能够用下面的方式传递url参数

res = requests.get(
    url = "http://www.baidu.com/",
    params = {
        "wd":"iphone",
        "res_spt":"1"
    },
    proxies = proxies
)

  

b、构建请求消息头

有的时候,咱们须要自定义一些http的消息头

每一个消息头也就是一种键值对的格式存放数据,在requests,只须要把抓包中的请求头信息放在一个字典中,而后传递headers便可

res = requests.get(
    url = "http://www.baidu.com/",
    headers = {
        "Host": "192.168.3.1",
        "User-Agent":"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36",
        "Accept-Language":"zh-CN,zh;q=0.8,en-US;q=0.6,en;q=0.4",
        "Accept-Encoding":"gzip, deflate, sdch"
        },
    params = {
        "wd":"iphone",
        "res_spt":"1"
    },
    proxies = proxies
)

  

 

c、构建请求的消息体

当咱们进行api接口测试的时候,根据接口规范,构建的http请求,一般须要构建消息体

http的消息体就是一串字节,里面包含了一些信息,这些信息多是文本,好比html网页做为消息体,也多是视频,音频信息

消息体可能很短,只有一个字节,好比字符a,也可能很长,有几百个字节

最多见的消息体格式固然是表示网页内容的html

当时在web api接口测试中,常见的HTTP消息体的格式有三种,urlencoded,json,xml

注意:消息体采用什么格式,是由开发人员设计决定的,开发人员也能够自定义格式,可是咱们一般不会自定义的

 

xml格式

前面时候了,消息体就是存放信息的地方,信息的格式彻底取决于设计者的需求,若是设计者决定使用xml格式传输一段信息,用requests库,只须要这样就能够了

 

playload = """
    <?xml version="1.0"?>
    <methodCall>
        <methodName>examples.getStateName</methodName>
        <params>
            <param>
                <value><i4>41</i4></value>
            </param>
        </params>
    </methodCall>"""

res2 = requests.post(
    url = "http://www.baidu.com/",
    headers = {
        "Host": "192.168.3.1",
        "User-Agent":"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36",
        "Accept-Language":"zh-CN,zh;q=0.8,en-US;q=0.6,en;q=0.4",
        "Accept-Encoding":"gzip, deflate, sdch",
        "Content-Type": "text/xml"
        },
    data=playload.encode("utf-8"),
    proxies = proxies
)

  

因为消息体都是字节串,咱们直接把字符串使用utf-8解码,而后传递给data参数便可,这里须要注意,须要设置Content-type=text/xml

 

 

 

 

使用data参数,存储消息体的数据,若是传递的是一个字符串,在http请求中,须要编码为字节码,默认的编码格式latin-1,这种编码格式是不支持中文的;一般咱们使用utf-8的编码格式

经过fiddler抓包

 

 

 

查看请求的原始信息

 

 

 

 

 

 

Urlencoded格式

这种格式的消息体就是一个key-value键值对的格式存放数据,以下所示

key1=value1&key2=value2

 

Requests发送这样的数据,固然能够直接把这种格式的字符串传入到data参数里;可是这样写的话,若是参数自己就有特殊字符,好比等号,就会有歧义

咱们还有更方便的方法,只须要将这些键值对的数据构建一个字典,以下

playload = {
    "key1":"value1",
    "key2":"value2"
}

res2 = requests.post(
    url = "http://www.example.com",
    headers = {
        "User-Agent":"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36",
        "Accept-Language":"zh-CN,zh;q=0.8,en-US;q=0.6,en;q=0.4",
        "Accept-Encoding":"gzip, deflate, sdch",
        "Content-Type": "application/x-www-form-urlencoded;charset=utf-8"
        },
    data=playload,
    proxies = proxies
)

  

这里须要注意下面2个地方

 

 

 

 

经过fiddler抓包

先看请求头

 

 

 

这里明显能够看到,请求头和请求体中间有一个空行

 

 

 

看下请求体中的数据

 

 

 

 

Json格式的消息体

Json字符串一概用双引号,不能用单引号

Json字符串最后一个元素的后面不能加逗号

 

其实咱们要把数据放到消息体中,最终的数据都是字节串,也就是把str.encode()

json格式当前被web api接口普遍采用

json是一种表示数据的语法格式,他和python表示数据的语法很是像

json格式有两种方式构建消息体

方式1

playload = {"title": "test", "sub": [1, 2, 3]}
res2 = requests.post(
    url = "http://www.example.com",
    headers = {
        "User-Agent":"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36",
        "Accept-Language":"zh-CN,zh;q=0.8,en-US;q=0.6,en;q=0.4",
        "Accept-Encoding":"gzip, deflate, sdch",
        "Content-Type": "application/json;charset=utf-8"
        },
    json=playload,
    proxies = proxies
)

  

注意下面这里

 

 

 

方式2

import json
playload = {"title": "test", "sub": [1, 2, 3]}
res3 = requests.post(
    url = "http://www.example.com",
    headers = {
        "User-Agent":"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36",
        "Accept-Language":"zh-CN,zh;q=0.8,en-US;q=0.6,en;q=0.4",
        "Accept-Encoding":"gzip, deflate, sdch",
        "Content-Type": "application/json;charset=utf-8"
        },
    data = json.dumps(playload,ensure_ascii=False).encode("utf-8"),
    proxies = proxies
)

  

注意下面这里

 

 

四、requests库的响应

a、检查HTTP响应状态码

要检查HTTP响应的状态码,直接经过response对象的status_code属性获取

import json
playload = {"title": "test", "sub": [1, 2, 3]}
res3 = requests.post(
    url = "http://www.example.com",
    headers = {
        "User-Agent":"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36",
        "Accept-Language":"zh-CN,zh;q=0.8,en-US;q=0.6,en;q=0.4",
        "Accept-Encoding":"gzip, deflate, sdch",
        "Content-Type": "application/json;charset=utf-8"
        },
    data = json.dumps(playload,ensure_ascii=False).encode("utf-8"),
    proxies = proxies
)


print(res3.status_code)

  

运行结果发现返回的结果状态码就是200

 

 

 

 

若是故意写一个不存在的地址

import requests

proxies = {
    "http":"127.0.0.1:8888",
    "http1": "127.0.0.1:8888"
}

res = requests.get(
    url = "http://192.168.3.1/html/index4.html",
    proxies = proxies
)

print(res.status_code)

  

运行结果发现返回的状态码就是404

 

 

 

 

b、检查响应的消息头

要检查HTTP响应的消息头,直接经过response对象的header属性获取

import json
import requests
import pprint
playload = {"title": "test", "sub": [1, 2, 3]}
proxies = {
    "http":"127.0.0.1:8888",
    "http1": "127.0.0.1:8888"
}
res3 = requests.post(
    url = "http://www.example.com",
    headers = {
        "User-Agent":"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36",
        "Accept-Language":"zh-CN,zh;q=0.8,en-US;q=0.6,en;q=0.4",
        "Accept-Encoding":"gzip, deflate, sdch",
        "Content-Type": "application/json;charset=utf-8"
        },
    data = json.dumps(playload,ensure_ascii=False).encode("utf-8"),
    proxies = proxies
)


print(pprint.pprint(dict(res3.headers)))

  

结果以下

 

 

 

 

 

 

 

c、检查响应消息体的文本内容

前面咱们已经说过,要获取响应的消息体的文本内容,直接经过response对象的text属性便可获取

import requests
import pprint
#
proxies = {
    "http":"127.0.0.1:8888",
    "http1": "127.0.0.1:8888"
}
#
res = requests.get(
    url = "http://mirrors.sohu.com",
    proxies = proxies
)
#
#
# print(res.text)
print(pprint.pprint(dict(res.headers)))
print(res.encoding)

  

  

响应体其实也是字节串,可是咱们调用text方法没有设置解码格式,他是怎么解码?他是根据响应头的contend-type来决定解码格式,有的时候会指定,可是大部分不会指定

咱们

 

 

 

 

咱们能够看到咱们打印的解码格式,和content-Type中是同样的

 

 

 

 

若是有的时候中文解码出来是乱码,咱们能够手动指定解码格式

 

 

 

 

 

若是咱们想打印响应体的字节串可使用content方法

 

 

 

 

 

五、session

a、原理

咱们来思考一个问题,一个网站,好比一个购物网站,服务成千上万的的客户,那么多客户同时访问网站,挑选物品,购物估算,都是经过hTTP请求来访问网站的,这个网站的服务端怎么区分每一个HTTP请求呢?网站的服务端是怎么实现的?

一种最多见的方式就是:经过Session+cookies机制

session翻译成中文就是会话的意思

session大致的原理以下面2个图

 

 

 

 

 

 

 

 

 

http协议规定了,网站的服务端放HTTP响应的消息头set-Cookies里面的数据,叫作cookies数据,浏览器客户端必需要保存下来。并且后续访问该网站,必须在http的请求头Cookies中携带保存的全部的cookie数据

用户使用客户端登录服务端,服务端进行验证,好比验证用户名和密码,验证经过后,服务端系统高就会为此次登录建立一个seesion,同时建立一个惟一的sessionID。标志这个session。而后,服务端经过HTTP响应,把sessionID告诉客户端,客户端在后面的HTTP请求的消息头,都要包含这个sessionID。这样服务端就会知道,这个供求对应哪一个session,从而知道此次的请求对应哪一个用户;

 

 

 

 

从上图能够看出,服务端是经过HTTP的响应头set-cookies把产生的sessionID告诉客户端。

 

 

 

 

客户端的后续请求,是经过HTTP请求的请求头Cookies告诉服务端他所持有的sessionid的

 

b、request库支持session的

request处理session-cookies

咱们在python代码中若是接收到服务器的http响应,其余set-cookies的数据怎么保存呢?后续怎么样把请求消息头中cookies中呢?

前面学过HTTP响应中如何获取响应头,构建请求怎么设置请求头,彻底能够处理。

可是requests库为咱们这个处理

requests库给咱们提供了一个session类。经过这个类,无需咱们操心cookies和session这个事情。reqeusts库会自动帮咱们保存服务端发挥的cookies数据,HTTP请求自动在消息头中放入cookies数据

以下所示

import requests
import json
session = requests.session()

playload = {"title": "test", "sub": [1, 2, 3]}
proxies = {
    "http":"127.0.0.1:8888",
    "http1": "127.0.0.1:8888"
}

res = session.post(
    url = "http://www.example.com",
    headers = {
        "User-Agent":"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36",
        "Accept-Language":"zh-CN,zh;q=0.8,en-US;q=0.6,en;q=0.4",
        "Accept-Encoding":"gzip, deflate, sdch",
        "Content-Type": "application/json;charset=utf-8"
        },
    data = json.dumps(playload,ensure_ascii=False).encode("utf-8"),
    proxies = proxies
)



res = session.get()
相关文章
相关标签/搜索