一季蚂、接口自動(dòng)化介紹
1.簡(jiǎn)介
[接口自動(dòng)化]是提高測(cè)試效率和質(zhì)量的重要手段之一。
2.為什么要做接口自動(dòng)化
相對(duì)于UI自動(dòng)化而言停蕉,接口自動(dòng)化具有更大的價(jià)值隧膘。
為了優(yōu)化轉(zhuǎn)化路徑或者提升用戶體驗(yàn),APP/web界面的按鈕控件和布局幾乎每個(gè)版本都會(huì)發(fā)生一次變化述呐,導(dǎo)致自動(dòng)化的代碼頻繁變更惩淳,沒(méi)有起到減少工作量的效果。
而接口一旦研發(fā)完成乓搬,后期重構(gòu)/大幅度修改的頻率則比較低.因而做接口自動(dòng)化性價(jià)比還是很高的思犁,對(duì)于迭代版本舊有功能的回歸,beta測(cè)試进肯,線上回歸都能起到事半功倍的作用激蹲。
3.接口自動(dòng)化兩大類
1、為模擬測(cè)試數(shù)據(jù)而開(kāi)展的接口自動(dòng)化
這種接口自動(dòng)化大多是單次執(zhí)行江掩,目的很明確是為了功能測(cè)試創(chuàng)造測(cè)試數(shù)據(jù)学辱,節(jié)約人工造數(shù)據(jù)的時(shí)間和人工成本,提高功能測(cè)試人員的測(cè)試效率环形。
2策泣、在功能測(cè)試之前提前發(fā)現(xiàn)錯(cuò)誤而開(kāi)展的接口自動(dòng)化
這種接口自動(dòng)化的工作流程跟功能測(cè)試一樣,需要設(shè)計(jì)接口測(cè)試用例斟赚,然后執(zhí)行接口測(cè)試用例着降。
說(shuō)白了就是對(duì)單接口進(jìn)行功能校驗(yàn)差油,包括接口參數(shù)的必填性拗军、長(zhǎng)度字符類型限制任洞、入?yún)⒚杜e值等是否正確、響應(yīng)數(shù)據(jù)是否正確等進(jìn)行校驗(yàn)发侵。
4.插件自動(dòng)安裝
1交掏、在項(xiàng)目根目錄創(chuàng)建文件:requirements.txt
2、在文件中寫入需要安裝的插件名
requirements.txt 內(nèi)容
pytest
requests
pytest-html
pytest-xdist
pytest-ordering
pytest-rerunfailures
pytest-base-url
allure-pytest
二刃鳄、Requests簡(jiǎn)介
1.Requests是基于urllib盅弛,使用Apache2 許可證開(kāi)發(fā)HTTP庫(kù)。其在python內(nèi)置模塊的基礎(chǔ)上進(jìn)行了高度封裝叔锐,使得Requests能夠輕松完成瀏覽器相關(guān)的任何操作挪鹏。
2.接口測(cè)試流程
發(fā)起請(qǐng)求: 通過(guò)HTTP庫(kù)向目標(biāo)站點(diǎn)發(fā)起請(qǐng)求,等待目標(biāo)站點(diǎn)服務(wù)器響應(yīng)愉烙。
獲取響應(yīng): 若服務(wù)器正常響應(yīng)讨盒,會(huì)返回一個(gè)Response,該Response
即為獲取得頁(yè)面內(nèi)容步责,Response可以是HTML返顺、JSON、字符串蔓肯、
二進(jìn)制數(shù)據(jù)等數(shù)據(jù)類型遂鹊。
解析內(nèi)容:利用正則表達(dá)式、網(wǎng)頁(yè)解析庫(kù)對(duì)HTML進(jìn)行解析蔗包;
將json數(shù)據(jù)轉(zhuǎn)為JSON對(duì)象進(jìn)行解析秉扑;保存我們需要得二進(jìn)制數(shù)據(jù)
(圖片、視頻)调限。
內(nèi)容斷言:根據(jù)解析內(nèi)容斷言期望結(jié)果邻储。
3.Requests總覽
使用requests發(fā)送get請(qǐng)求
以訪問(wèn)百度為例,訪問(wèn)百度時(shí)旧噪,是使用的get請(qǐng)求吨娜,所以這里調(diào)
用requests.get()方法,將返回結(jié)果用resp接收淘钟,這里因?yàn)?響應(yīng)結(jié)果是亂碼宦赠,所以這里把返回結(jié)果編碼設(shè)置為utf-8
import requests
def fun1():
resp = requests.get("http://www.baidu.com") #request發(fā)送不帶參數(shù)的get請(qǐng)求
resp.encoding="utf-8" #防止中文亂碼,設(shè)置響應(yīng)內(nèi)容編碼格式
print(resp.status_code) #輸出響應(yīng)狀態(tài)碼
print(resp.text) #獲取響應(yīng)的文本信息
if __name__ == "__main__":
fun1()
#發(fā)送get請(qǐng)求帶參數(shù)--請(qǐng)求格式為字典,使用params參數(shù)
以訪問(wèn)百度為例米母,這里是在百度搜索python勾扭,后面增加了一個(gè)參數(shù)
wd,也可以直接用
resp = requests.get(["](http://www.baidu.com/s """)http://www.baidu.com/s?wd=python")铁瞒,下面把url和請(qǐng)求參數(shù)分別用變量接收
def fun2():
data_dict={"wd":"python"}
req_url="http://www.baidu.com/s"
resp = requests.get(url=req_url,params=data_dict)
print(resp.status_code)
使用requests發(fā)送post請(qǐng)求
post請(qǐng)求的參數(shù)分為兩種情況妙色,請(qǐng)求頭中Content-type是
application/x-www.form-url,后面的參數(shù)就是data慧耍,
請(qǐng)求頭中Content-type是application/json身辨,參數(shù)就用json
response = request.post(url,data=None,json=None)
data:參數(shù)接收f(shuō)orm表單數(shù)據(jù)丐谋,后臺(tái)會(huì)自動(dòng)附加form表單請(qǐng)求信息頭
header={"Content-Type":"application"}
json:參數(shù)接收json數(shù)據(jù)時(shí),后臺(tái)會(huì)自動(dòng)附加json表單請(qǐng)求信息頭
header={“Content-Type”:“application/json”}
data參數(shù)提交數(shù)據(jù)
import requests
url = 'http://httpbin.org/post'
"""帶data數(shù)據(jù)的post"""
data = {'key1':'value1','key2':'value2'}
response = requests.post(url,data=data)
print(response.status_code)
print(response.text)
"""帶json數(shù)據(jù)的post"""
import requests
url_login = "http://ihrm-java.itheima.net/api/sys/login"
#無(wú)論表單data還是json煌珊,都是用字典發(fā)送請(qǐng)求
login_json = {
"mobile" :"17743533546",
"password" : "123456"
}
response = requests.post(url=url_login,json=login_json)
#查看響應(yīng)
print(response.json())
響應(yīng)公共方法
請(qǐng)求方法的返回值response為Response對(duì)象号俐,我們可以從
這個(gè)對(duì)象中獲取所有我們想要的響應(yīng)信息。
response.status_code 狀態(tài)碼
response.url 請(qǐng)求url
response.encoding 查看響應(yīng)頭部字符編碼
response.headers 頭信息
response.cookies cookie信息
response.text 文本形式的響應(yīng)內(nèi)容
response.content 字節(jié)形式的響應(yīng)內(nèi)容
response.json() JSON形式的響應(yīng)內(nèi)容
import requests
# 1). 訪問(wèn)百度首頁(yè)的接口`http://www.baidu.com`定庵,獲取以下響應(yīng)數(shù)據(jù)
response = requests.get("http://www.baidu.com")
# 2). 獲取響應(yīng)狀態(tài)碼
print("響應(yīng)狀態(tài)碼",response.status_code)
# 3). 獲取請(qǐng)求URL
print("請(qǐng)求url",response.url)
# 4). 獲取響應(yīng)字符編碼
print("響應(yīng)字符編碼",response.encoding)
# 5). 獲取響應(yīng)頭數(shù)據(jù)
print("響應(yīng)頭數(shù)據(jù)",response.headers)
#提取響應(yīng)頭數(shù)據(jù)中某個(gè)鍵的值
print("Content-Type",response.headers.get("Content-Type"))
# 6). 獲取響應(yīng)的cookie數(shù)據(jù)
print("cookie數(shù)據(jù)",response.cookies)
print("提取指定的cookie",response.cookies.get("BDORZ"))
# 7). 獲取文本形式的響應(yīng)內(nèi)容
print("文本形式內(nèi)容",response.text)
# 8). 獲取字節(jié)形式的響應(yīng)內(nèi)容
print("響應(yīng)內(nèi)容",response.content)
其他
如果需要為請(qǐng)求添加請(qǐng)求頭數(shù)據(jù)吏饿,只需要傳遞一個(gè)字典類型的
數(shù)據(jù)給 headers 參數(shù)就可以了
"""
1. 請(qǐng)求IHRM項(xiàng)目的登錄接口,URL: http://ihrm-java.itheima.net/api/sys/login
2. 請(qǐng)求頭: Content-Type: application/json
3. 請(qǐng)求體: {"mobile":"17743533546", "password":"123456"}
"""
#設(shè)置請(qǐng)求頭
import requests
url_login = "http://ihrm-java.itheima.net/api/sys/login"
#請(qǐng)求頭是一個(gè)鍵值對(duì)
header = {
"Content-Type":"application/json"
}
login_data = {
"mobile":"17743533546",
"password":"123456"
}
response = requests.post(url=url_login,json=login_data,headers=header)
response.encoding = 'utf-8'
print(response.json())
"""下載圖片"""
import requests
import matplotlib.pyplot as plt
url = 'https://cn.bing.com/images/search?view=detailV2&ccid=qr8JYj0b&id=6CEE679B0BCE19C94FB9C7595986720942C92261&thid=OIP.qr8JYj0bcms3xayruiZmnAHaJQ&mediaurl=https%3a%2f%2ftse1-mm.cn.bing.net%2fth%2fid%2fR-C.aabf09623d1b726b37c5acabba26669c%3frik%3dYSLJQglyhllZxw%26riu%3dhttp%253a%252f%252fp1.ifengimg.com%252f2019_02%252f95A41E54C3C8EB3B3B148A30CE716314B0AED504_w1024_h1280.jpg%26ehk%3d2EhKcVkSnCvT6uBfgisn%252fdwtghMXFWjGa5WgqEbBSPc%253d%26risl%3d%26pid%3dImgRaw&exph=1280&expw=1024&q=%e7%9f%b3%e5%8e%9f%e9%87%8c%e7%be%8e&simid=607996751665040666&FORM=IRPRST&ck=399D74E04F8507D6711ADC8F53A714D7&selectedIndex=0&ajaxhist=0&ajaxserp=0'
response = requests.get(url)
img = response.content
with open('shiyuanlimei.jpg','wb') as f:
f.write(img)
"""接口參數(shù)關(guān)聯(lián)請(qǐng)求"""
datas = {
"username":"qcj",
"password":"123456"
}
login_url = "http://www.fanyunedu.com:5000/general/login_token"
rep = requests.post(url=login_url,data = datas)
req_json = rep.json()
token =req_json['data']
headers = {
"auth-token":token
}
t_url="http://www.fanyunedu.com:5000/general/userinfo_token"
t_req = requests.get(url=t_url,headers=headers)
"""加密接口請(qǐng)求"""
uid,name,password,salt='3','qcj','123456','LZ7dYxCj5S68ucAh'
import hashlib
hl = hashlib.md5()
hl.update('{}-{}-{}-{}'.format(uid,name,password,salt).encode('utf-8'))
sigh = hl.hexdigest()#對(duì)hl對(duì)象中保存的字段進(jìn)行md5的加密算法
datas={"uid":"3","sign":sigh}
url_data = "http://www.fanyunedu.com:5000/general/userinfo_sign"
req = requests.post(url=url_data,json=datas)
三蔬浙、Yaml知識(shí)點(diǎn)
1.Yaml簡(jiǎn)介
YAML 是一種可讀性非常高猪落,與程序語(yǔ)言數(shù)據(jù)結(jié)構(gòu)非常接近。同時(shí)具備豐富的表達(dá)能力和可擴(kuò)展性畴博,并且易于使用的數(shù)據(jù)標(biāo)記語(yǔ)言许布。
其實(shí)YAML文件也是一種配置文件,但是相較于ini绎晃,conf配置文件來(lái)說(shuō)蜜唾,更加的簡(jiǎn)潔,操作簡(jiǎn)單庶艾,還能存放不同類型的數(shù)據(jù)袁余;而像ini存儲(chǔ)的值就都是字符串類型,讀取之后還要手動(dòng)轉(zhuǎn)換
2.YAML的基本語(yǔ)法規(guī)則
大小寫敏感
使用縮進(jìn)表示層級(jí)關(guān)系
縮進(jìn)時(shí)不允許使用Tab鍵咱揍,只允許使用空格颖榜。(可以將你的ide的tab按鍵輸出替換成4個(gè)空格)
縮進(jìn)的空格數(shù)目不重要,只要相同層級(jí)的元素左側(cè)對(duì)齊即可
表示注釋
3.YAML支持的數(shù)據(jù)結(jié)構(gòu)
對(duì)象:鍵值對(duì)的集合煤裙,又稱為映射(mapping)/ 哈希(hashes) / 字典(dictionary)
數(shù)組:一組按次序排列的值掩完,又稱為序列(sequence) / 列表(list)
純量(scalars):?jiǎn)蝹€(gè)的、不可再分的值
4.YAML硼砰,對(duì)象數(shù)據(jù)類型
對(duì)象的一組鍵值對(duì)且蓬,使用冒號(hào)結(jié)構(gòu)表示。
animal: dogs
轉(zhuǎn)換成Python數(shù)據(jù)結(jié)構(gòu)题翰,如下:
{'animal': 'dogs'}
將所有鍵值對(duì)賦值恶阴。
hash: { name: Steve, foo: bar }
轉(zhuǎn)換成Python數(shù)據(jù)結(jié)構(gòu),如下:
{'hash': {'name': 'Steve', 'foo': 'bar'}}
將列表賦值
lists : [1,2,3]
轉(zhuǎn)換成Python數(shù)據(jù)結(jié)構(gòu)豹障,如下:
{'lists': [1, 2, 3]}
將元組賦值
tuples : (1,2,3)
轉(zhuǎn)換成Python數(shù)據(jù)結(jié)構(gòu)冯事,如下:
{'tuples': '(1,2,3)'}
總結(jié)
當(dāng)賦值列表血公、鍵值對(duì)時(shí),轉(zhuǎn)換成Python數(shù)據(jù)結(jié)構(gòu)是可以直接當(dāng)列表累魔、字典使用的够滑;
當(dāng)賦值元組時(shí),轉(zhuǎn)換后也是字符串
最終輸出的都是字典類型版述,可以通過(guò)key獲取對(duì)應(yīng)的值
以 - 開(kāi)頭的行表示構(gòu)成一個(gè)數(shù)組
四梯澜、python+requests+pytest+yaml+allure接口自動(dòng)化框架
四.框架的介紹:
1.common層構(gòu)建基礎(chǔ)類庫(kù):為了提高測(cè)試用例的可維護(hù)性性和復(fù)用性,其中包括日志輸出,接口統(tǒng)一發(fā)送請(qǐng)求,yaml文件的讀取,
寫入,清除的方法
2.data層:存放測(cè)試用例yaml數(shù)據(jù)
3.logs層:存放日志
4.reports層:存放生成的allure報(bào)告
5.temps層:存放生成的臨時(shí)報(bào)告
6.testcase層:測(cè)試用例
7.pytest.ini:配置文件
8.requirements.txt:依賴包
9.run.py:自動(dòng)化框架運(yùn)行腳本的文件,然后會(huì)在reports生成allure報(bào)告
框架的使用說(shuō)明:
1.環(huán)境配置:需要在pycharm終端里安裝requirements.txt依賴包,輸入pip install -requirements.txt部署環(huán)境
2.編寫測(cè)試用例數(shù)據(jù)是用yaml文件進(jìn)行傳參,其中包含測(cè)試所有API的參數(shù),這個(gè)文件可以包括
接口名稱(name),請(qǐng)求(request),請(qǐng)求方法(menthod),請(qǐng)求路徑(URL),請(qǐng)求參數(shù)(params)
舉例:
- name: 獲取接口統(tǒng)一鑒權(quán)碼token接口
request:
method: get
url: https://api.weixin.qq.com/cgi-bin/token
params:
grant_type: client_credential
appid: XXXXXXXXXXXX
secret: XXXXXXXXXXXXX
3.測(cè)試用例以test_XXX命名,XXX是測(cè)試用例的名字,其中包括allure標(biāo)記的裝飾器,數(shù)據(jù)驅(qū)動(dòng),斷言,
@allure.story(),allure.dynamic.title()是allure標(biāo)記的裝飾器
@pytest.mark.parametrize("caseinfo", read_testcase("./data/test_get_token.yaml"))
這行代碼使用了pytest框架提供的 @pytest.mark.parametrize()裝飾器,具體含義是read_testcase()yaml文件
讀取的函數(shù)從路徑"./data/test_get_token.yaml"文件中讀取到測(cè)試用例數(shù)據(jù)集作為參數(shù),將其命名為caseinfo,并
傳遞給被裝飾器的測(cè)試函數(shù).
test_get_token()的測(cè)試函數(shù),該函數(shù)使用了參數(shù)化方式運(yùn)行多組測(cè)試用例,每組測(cè)試用例都是一個(gè)字典函數(shù),包含了請(qǐng)求參數(shù)
和預(yù)期結(jié)果信息,用yaml數(shù)據(jù)格式進(jìn)行value:key方式進(jìn)行傳參.
斷言用是pytest自帶的斷言方式assert
舉例:
@pytest.mark.parametrize("caseinfo", read_testcase("./data/test_get_token.yaml"))
@allure.story("獲取token接口")
def test_get_token(self, caseinfo):
allure.dynamic.title("獲取token")
method = caseinfo["request"]["method"]
url = caseinfo["request"]["url"]
params = caseinfo["request"]["params"]
res = RequestUntil().send_request(method=method, url=url, params=params)
print(res.json()["access_token"])
write_yaml(res.json()["access_token"])
assert res.status_code== 200
assert "access_token" in res.text
4.執(zhí)行測(cè)試
點(diǎn)擊run.py文件.執(zhí)行腳本,然后會(huì)在reports包里生成一份allure報(bào)告,點(diǎn)擊idex.html,點(diǎn)擊瀏覽器就可以查看
本地allure報(bào)告