1.金字塔模型
把软件测试从宏观的思维分为三层,最底层的是单元测试,中间层是API测试,最上层是UI⾃动化测试,如下所示:
基于微服务的架构模型中,金字塔模型如下图所示:
2.HTTP协议
总结三次握⼿具体为:
第⼀次握⼿:起初两端都处于CLOSED关闭状态,Client将标志位SYN置为1,随机产⽣⼀个值seq=x,并将该数据包发送给Server,Client进⼊SYN-SENT状态,等待Server确认;
第⼆次握⼿:Server收到数据包后由标志位SYN=1得知Client请求建⽴连接,Server将标志位SYN和ACK都置为1,ack=x+1,随机产⽣⼀个值seq=y,并将该数据包发送给Client以确认连接请求,Server进⼊SYN-RCVD状态,此时操作系统为该TCP连接分配TCP缓存和变量;
第三次握⼿:Client收到确认后,检查ack是否为x+1,ACK是否为1,如果正确则将标志位ACK置为1,
ack=y+1,并且此时操作系统为该TCP连接分配TCP缓存和变量,并将该数据包发送给Server,Server检查ack是否为y+1,ACK是否为1,如果正确则连接建⽴成功,Client和Server进⼊ESTABLISHED状态,完成三次握⼿,随后Client和Server就可以开始传输数据。
3.HTTP完整请求
在API的自动化测试中,我们更多关注的是HTTP应用层的交互,因为即使主流的架构如微服务架构,它的通信模式也是基于REST API轻量级的通信模式。在HTTP的协议中,一个完整的HTTP请求流程具体为:
(1)客户端与服务端之间建立TCP的连接请求
(2)客户端向服 务端发送Request的请求
1)请求地址
2)请求方法
3)请求头
4)请求参数
(3)服务端Response相应回复给客户端
1)协议状态码
2)响应头
3)响应数据
(4)客户端与服务端之间关闭TCP的连接请求
4.通信模式
(1)同步交互
1)容易超时,客户端发送请求后,服务端迟迟没有回应客户端的请求
2)如果请求存在大的计算量和逻辑存在问题,就会导致请求堵塞
(2)异步交互
1)在异步的交互中,客户端和服务端互相不需要 关注对⽅的存在,只需要关注对应的MQ的消息,客户端与服务端的交互主要是会通过MQ的消息中间作为消息的传递来进⾏交互的
5.常用请求方法
Post:不仅可以进行添加,还可以删除和修改
Put和Delete:也不一定完全可以修改和删除,因为存在安全隐患
6.常用协议状态码
(1)200:请求成功
(2)301:永久重定向 Moved Permanently(会按照Location首部字段提示的新URI更新书签。页面内容更新,且地址栏网址也更新)
(3)302:临时重定项 Found(不更新书签。页面内容更新,但地址栏网址不更新)
400开头都是客户端的错误
(4)40:Bad Request 客户端请求错误(请求头或者请求参数不对)
(5)401:Unauthorized (该状态码表示发送的请求需要有通过 HTTP 认证的认证信息)
(6)403:Forbidden (未获得文件系统的访问授权,访问权限出现某些问题)
(7)404:请求的资源不存在
(8)405:不被允许的请求⽅法
500开头的都是服务器的错误
(9)500:服务器内部错误 (服务器端在执行请求时发生了错误)
(10)504:GateWay Timeout(服务器假死,能用但是没有及时从服务器收到请求)
7.请求头/响应头
8.常用请求数据格式
序列化JSON格式数据:是字典类型
9.
import requests
r=requests.get(url='http://localhost:5000/login')
print('状态协议码:',r.status_code)
print('响应头:',r.headers)
#只能是JSON数据
print('响应数据:',r.json())
#表单、JSON、XML数据
print('响应数据:',r.text)
print('返回二进制的内容',r.content)
print('响应时间:',r.elapsed.total_seconds())
print('cookies:',r.cookies)
10.JSON类型
import requests
r=requests.post(url='http://localhost:5000/login',
json={'username':'liuxun','password':'admin','sex':'女','age':21},
headers={"Content-Type":"application/json"})
print(r.status_code)
print(r.json())
11.Data类型
import requests
import json
r=requests.post(url='http://localhost:5000/login',
data=json.dumps({'username':'liuxun','password':'admin','sex':'女','age':21}),
headers={"Content-Type":"application/json"})
print(r.status_code)
print(r.json())
12.实战
import unittest
import json
import requests
class ApiTest(unittest.TestCase):
def setUp(self) -> None:
self.url='http://localhost:5000/login'
self.data={'username':'liuxun','password':'admin','sex':'女','age':21}
self.headers={'Content-Type':'application/json'}
def test_login_001(self):
r=requests.get(url=self.url)
self.assertEqual(r.status_code,200)
self.assertEqual(r.json()['status'],0)
self.assertEqual(r.json()['data'],'this is a login page')
def test_login_002(self):
r=requests.post(url=self.url,
json=self.data,
headers=self.headers)
self.assertEqual(r.status_code,200)
self.assertEqual(r.json()['username'],'liuxun')
def test_login_username_null(self):
'''校验username参数为空的错误信息'''
r=requests.post(url=self.url,
json={'password':'admin','sex':'女','age':21},
headers={"Content-Type":"application/json"})
self.assertEqual(r.status_code,400)
self.assertEqual(r.json()['message']['username'],'用户名不能为空')
def test_login_password_null(self):
'''校验password参数为空的错误信息'''
r=requests.post(url=self.url,
json={'username':'liuxun','sex':'女','age':21},
headers={"Content-Type":"application/json"})
self.assertEqual(r.status_code,400)
self.assertEqual(r.json()['message']['password'],'账户密码不能为空')
def test_login_age_not_int(self):
'''校验年龄不为整型的错误信息'''
r=requests.post(url=self.url,
json={'username':'liuxun','password':'admin','sex':'女','age':'qsd'},
headers={"Content-Type":"application/json"})
self.assertEqual(r.status_code,400)
self.assertEqual(r.json()['message']['age'],'年龄必须为正正数')
def test_login_sex_boy_girl(self):
'''校验性别不是男的或者不是女的'''
r=requests.post(url=self.url,
json={'username':'liuxun','password':'admin','sex':"qwds",'age':21},
headers={"Content-Type":"application/json"})
self.assertEqual(r.status_code,400)
self.assertEqual(r.json()['message']['sex'],'性别只能是男或者女')
def test_jinyan(self):
r=requests.post(url='http://m.cyw.com/Home/ComSearch/search',
data={'k':'金燕'},
headers={'content_tyoe':'text/html; charset=utf-8','user-agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36'})
self.assertEqual(r.status_code,200)
self.assertEqual(r.json()['procedure'],9)
print(r.json())
def test_wuyuan(self):
r=requests.post(url='http://m.cyw.com/Home/ComSearch/search_com',
data={'k':'婺源'},
headers={'content_tyoe':'text/html; charset=utf-8','user-agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36'})
self.assertEqual(r.status_code,200)
self.assertEqual(r.json()['procedure'],8)
print(r.json())
if __name__ == '__main__':
unittest.main(verbosity=2)