你想知道的接口自動化測試幹貨(一)

喜歡看海的測試小白 2021-08-15 15:03:10 阅读数:24

本文一共[544]字,预计阅读时长:1分钟~
你想 想知道 知道 接口

pytest概念

pytest是一個單元測試框架,單元測試是指在軟件開發當中,針對軟件的最小單元(函數、方法)進行正確性的檢查測試。

單元測試主要做什麼?

1.測試發現:從多個文件裏面去找到我們的測試用例;

2.測試執行:按照一定的順序和規則去執行,並生成結果;

3.測試判斷:通過斷言判斷預期結果和實際結果的差异;

4.測試報告:統計測試進度,耗時,通過率,生成測試報告;

單元測試框架只是自動化測試框架中的組成部分之一。自動化測試框架中還包括:設計模式、數據驅動、關鍵字驅動、全局配置文件的封裝、日志監控、selenium和requests二次封裝、斷言、報告郵件......

pytest中的裝飾器@pytest.mark.parametrize()的基礎用法

所有的測試框架都離不開數據驅動,那數據驅動是什麼?

數據驅動:其實就是把我們測試用例的數據放到excel、yaml、csv、mysql。然後通過去改變數據到改變測試用例的執行結果。

@pytest.mark.parametrize(args_name,args_value)

args_name:參數的名稱

args_value:參數的值(支持格式:列錶、元組,字典列錶、字段元組,即:[]、()、[{},{},{}]、({},{},{})),值的注意的是,參數的值有多少個,這個方法就被執行多少次。

pytest默認的測試用例規則:(可以根據pytest.ini配置文件進行修改)

1.模塊名必須以test_或者_test開頭;

2.類名必須以Test開頭;

3.方法名必須以test開頭;

使用的方式

方式一:最基本的用法

import pytest
class TestApi:
@pytest.mark.parametrize('args', ['張三', '李四', '王五', '趙六'])
def test_01_api(self, args):
print(args)
if __name__ == '__main__':
pytest.main(['-vs', 'test_api.py'])
複制代碼

執行以上代碼,test_01_api用例會執行四次,分別將'張三', '李四', '王五', '趙六'打印出來。-vs指令參數錶示打印出較為詳細的日志信息。test_api.py錶示執行的文件。

執行結果:

image.png

方式二:解包的用法

若我們將傳入參數的格式進行變化,如下圖所示,參數的值寫成兩個list,測試用例就會執行兩次,而這兩次分別傳入兩個list。

image.png

現在我們傳入兩個參數名稱,如下圖所示,觀察運行結果會發現,每一個list中的第一個元素會傳給name,第二個元素會傳給age,這就是解包的用法,此方法與unittest框架中實現數據驅動的裝飾器ddt類似。

image.png

import pytest
class TestApi:
@pytest.mark.parametrize('name,age', [['張三', 20], ['王五', 21]])
def test_01_api(self, name, age):
print(name, age)
if __name__ == '__main__':
pytest.main(['-vs', 'test_api.py'])
複制代碼

Pytest結合yaml實現數據驅動

yaml簡介

yaml它是一個數據文件保存的一個數據格式,支持注釋、換行、裸字符串(最小單比特的數據)

yaml用途

(1)用於全局配置文件:環境、數據庫信息、賬號信息、日志格式、報告名稱。

(2)用於接口自動化裏面多一些複雜的多接口串聯。

(3)用於編寫接口測試用例。

yaml語法規則

(1)區分大小寫

(2)和Python一樣也是通過縮進的方式來錶示層級關系

(3)和縮進多少層無關,只和左邊是否對齊有關系

(4)#錶示注釋

yaml數據組成舉例

(1)map對象:鍵(空格)值

image.png

(2)數組(列錶):用一組橫線開頭

image.png

用來驗證yaml文件格式或者json文件格式是否正確的網站:www.bejson.com/

小試牛刀

(1)新建一個yaml文件data.yaml,編寫代碼如下:

image.png

-
api_name: 獲取網易新聞
api_request:
url: https://api.apiopen.top/getWangYiNews
method: post
headers:
Content-Type: application/json
params:
page: 1
count: 5
api_validate:
- eq: {code: 200}
複制代碼

(2)新建一個Python文件yaml_util.py,封裝讀取yaml文件數據的函數。

image.png

import yaml
# 讀取yaml文件內容的函數
def read_yaml():
with open('data.yaml', encoding='utf_8', mode='r') as f:
data = yaml.load(f, Loader=yaml.FullLoader)
return data
複制代碼

(3)新建一個Python文件test_api.py編寫測試用例

import pytest
import requests
from pytest_yaml.yaml_util import read_yam
class TestApi:
@pytest.mark.parametrize('args', read_yaml())
def test_01_api(self, args):
url = args['api_request']['url']
method = args['api_request']['method']
headers = args['api_request']['headers']
params = args['api_request']['params']
if method == 'get':
requests.get(url)
else:
resp = requests.post(url, json=params, headers= headers)
print(resp.json())
if __name__ == '__main__':
pytest.main(['-vs', 'test_api.py'])
複制代碼

運行結果:

image.png

(4)添加斷言

image.png 如上圖所示,獲取yaml文件中斷言的數據列錶,所有多個斷言,采用for循環遍曆,使用assert方法進行斷言,運行之後成功。

以上所實現的接口測試是最基礎的,采用了一個接口,執行一個測試用例,只有一次斷言。若在實際工作中使用,這遠遠是不够的。

接口實戰

獲取token鑒權碼接口

使用微信開放文檔中獲取Access token接口進行練習,接口文檔為:

image.png

由接口文檔可知,方法為Get,接口地址為:api.weixin.qq.com/cgi-bin/tok… ,接口需要傳入的參數為grant_type、appid、secret。

使用Python訪問該接口,將響應的值打印到控制臺,如下所示:

image.png

import unittest
import requests
class TestApi(unittest.TestCase):
def test_01_get_token(self):
url = " https://api.weixin.qq.com/cgi-bin/token"
params = {
"grant_type": "client_credential",
"appid": "xxxxxxxxxxxxx",
"secret": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
}
resp = requests.get(url, params=params)
print(resp.json())
複制代碼

添加斷言

(1)斷言返回的狀態碼是否為200 self.assertEqual(resp.status_code, 200)

(2) 斷言返回的結果中是否包含access_token self.assertIn('access_token', resp.text)

(3)斷言返回的結果中expires_in的值是否等於7200 self.assertEqual(dict_result['expires_in'], 7200)

反序列化

(1)把json格式的字符串轉化為字典格式dict_result = json.loads(resp.text)

(2)直接將響應的內容獲取為字典格式dict_result = resp.json()

import json
import unittest
import requests
class TestApi(unittest.TestCase):
def test_01_get_token(self):
url = " https://api.weixin.qq.com/cgi-bin/token"
params = {
"grant_type": "client_credential",
"appid": "xxxxxxxxxxxxx",
"secret": "xxxxxxxxxxxxxxxxxxx"
}
resp = requests.get(url, params=params)
print(resp.text, type(resp.text))
# 方法一:反序列化,把json格式的字符串轉化為字典格式
dict_result = json.loads(resp.text)
# 方法二:直接將響應的內容獲取為字典格式
# dict_result = resp.json()
# 斷言
# 斷言返回的狀態碼是否為200
self.assertEqual(resp.status_code, 200) # 狀態斷言
# 斷言返回的結果中是否包含access_token
self.assertIn('access_token', resp.text) # 業務斷言1
# 斷言返回的結果中expires_in的值是否等於7200
self.assertEqual(dict_result['expires_in'], 7200) # 業務斷言2
複制代碼

獲取公眾號已創建的標簽

接口文檔如下:

image.png

import unittest
import requests
class TestApi(unittest.TestCase):
# 定義一個全局變量、類變量
access_token = ""
# 獲取access_token
def test_01_get_token(self):
url = " https://api.weixin.qq.com/cgi-bin/token"
params = {
"grant_type": "client_credential",
"appid": "wx5046a51617ff683a",
"secret": "334c600a9fbbcadac918d5665d7b1d12"
}
resp = requests.get(url, params=params)
print(resp.text, type(resp.text))
# 反序列化,把json格式的字符串轉化為字典格式
dict_result = resp.json()
# 獲取鑒權碼access_token並保存
TestApi.access_token = dict_result['access_token']
# 斷言
# 斷言返回的狀態碼是否為200
self.assertEqual(resp.status_code, 200) # 狀態斷言
# 斷言返回的結果中是否包含access_token
self.assertIn('access_token', resp.text) # 業務斷言1
# 斷言返回的結果中expires_in的值是否等於7200
self.assertEqual(dict_result['expires_in'], 7200) # 業務斷言2
# 獲取公眾號已創建的標簽
def test_02_select_flag(self):
url = " https://api.weixin.qq.com/cgi-bin/tags/get"
params = {
"access_token": TestApi.access_token
}
resp = requests.get(url, params=params)
print(resp.json())
# 斷言返回的狀態碼是否為200
self.assertEqual(resp.status_code, 200) # 狀態斷言
# 斷言返回的結果中是否包含tags
self.assertIn('tags', resp.text) # 業務斷言
複制代碼

接口關聯

以上接口文檔可知,接口2的執行需要傳入接口1中返回的access_token,那麼,如何實現access_token的關聯呢?

(1)定義一個全局變量access_token = ""

(2)在接口1響應內容中獲取access_token的值並保存到全局變量中TestApi.access_token = dict_result['access_token']

(3)將全局變量access_token作為參數傳入接口2中 "access_token": TestApi.access_token

(4)可將全局變量獲取之後保存在yaml文件中。

Cookie,session,Token鑒權解决方案

什麼是cookie?

cookie是在服務器產生的存儲在客戶端的一小段文本信息。格式是字典,鍵值對。

cookie的分類

會話級:保存內存,當瀏覽器關閉就會消失。

持久化:保存硬盤,只有當失效時間到了才會被清除。

如何查看cookie?

image.png

cookie如何實現鑒權(原理)

當客戶第一次訪問服務器時,那麼服務器就會產生cookie,然後通過響應頭的方式在set-cookie裏面傳輸到客戶端,客戶端從第2-N次請求都會自動的帶上這些cookie。

致命的弱點:cookie保存在客戶端,對於一些敏感的信息,比如用戶名、密碼、身份證號這些信息都不安全。

用python實現一個登錄接口,並從響應中提取token。

接口為post請求,參數和響應結果如下所示: image.png

image.png

用python發送請求,代碼如下:

import requests
import unittest
import json
class TestApi(unittest.TestCase):
def test_01_api(self):
url = "http://api-store**************staff/login"
jsontext = {
"account": "188********",
"password": "123456"
}
data = {
"device_type": 30,
"system": 2,
"jsonText": json.dumps(jsontext)
}
headers = {
"Content-Type": "application/x-www-form-urlencoded"
}
resp = requests.post(url, data=data, json=json,headers=headers)
print(resp.text)
if __name__ == '__main__':
unittest.main()
複制代碼

執行結果如下:

image.png

通過正則錶達式取出token的值

 # 通過正則錶達式提取token的值
value = re.search('"token":"(.+?)"', resp.text)
print(value.group(1))
複制代碼

image.png

將獲取的token保存到全局變量中

import re
import requests
import unittest
import json
class TestApi(unittest.TestCase):
# 定義一個全局變量
token = ""
def test_01_api(self):
url = "http://api***********/login"
jsontext = {
"account": "188******",
"password": "123456"
}
data = {
"device_type": 30,
"system": 2,
"jsonText": json.dumps(jsontext)
}
headers = {
"Content-Type": "application/x-www-form-urlencoded"
}
resp = requests.post(url, data=data, json=json,headers=headers)
print(resp.text)
# 通過正則錶達式提取token的值
value = re.search('"token":"(.+?)"', resp.text)
# 將提取的token值保存為一個全局變量
TestApi.token = value.group(1)
# 後面需要用到token的操作可以直接使用全局變量
print(TestApi.token)
if __name__ == '__main__':
unittest.main()
複制代碼

如果在下個接口測試的時候我們需要傳入cookies,那麼我們就可以定義一個保存cookies的全局變量test_cookies = "",通過test_cookies = resp.cookies提取cookies並保存到全局變量test_cookies中,在下面接口測試中將cookies傳入,即:requests.post(url, data=data, json=json, headers=headers, cookies=test_cookies),這樣就實現了Cookie的鑒權。

session鑒權

當用戶第一次訪問服務器的時候,然後在服務器端會保存一個sessionid,這個sessionid是經過加密的,然後通過cookie把這個sessionid保存到客戶端,在請求服務器的時候只發送sessionid。

class TestApi(unittest.TestCase):
# 定義一個全局變量
session = ""
def test_01_api(self):
url = "http://**********"
TestApi.session = requests.Session()
# 請求的時候發送sessionid
res = TestApi.session.get(url=url)
print(TestApi.session)
print(res.json())
if __name__ == '__main__':
unittest.main()
複制代碼

session鑒權的致命弱點

對於瀏覽器來說sessionid是非常好用的,只需要在cookie中存一個字符串就行了,但是服務器必須存儲所有在線的用戶sessionid,那麼同時在線的人數越多開銷越大,嚴重影響了服務器的性能。當用戶量特別大的時候,會導致服務器崩潰。

token鑒權

上述的解决方案都是圍繞session,那麼能不能不用sessionid來解决呢?

如果不適用sessionid,如何確保數據是服務器生成的呢?怎麼去驗證呢?用戶信息存在哪?

於是有人想到了自己按照一定規則生成加密字符串,服務器只驗證不存儲,只要驗證通過說明是自己生成的,用戶信息存儲在加密字符串中,這樣性能、CORS(跨域資源共享)都能解决,而這個加密字符串就是token。

原文鏈接:blog.csdn.net/wtf0712/art…

當一個用戶登錄之後,就給他發送一個token令牌,下一次用戶再次請求的時候只需要帶上這個令牌。

token的加密方式:

對稱加密:DES AES

雙鑰加密:RSA

只加密不解密:MD5 SHA

token的分類:

access_token:有時間限制,限制在15分鐘

refresh_token:一般15天

cookie,session,token的相同點和區別:

相同點:都是用於做鑒權的,都是服務器產生的。

區別:

  1. cookie存儲在客戶端,session存儲在服務器,session的安全性比cookie高。所以一般情况下把重要的信息放到session,把不重要的放在cookie。

  2. session存在服務器內存,token存在服務器的文件或者數據庫中,token的好處是比session更節省服務器資源,token只需要在服務器解密即可。

在技術不斷進步的過程中,以上逐漸無法滿足用戶的需求,出現了新的問題:第三方支付、銀行、金融項目,對於安全性的要求更高,於是就出現了接口簽名sign,關於sign在本篇文章不做講解。

後記

我最近實在是太忙了,各種加班,都沒有時間學習了,就先寫到這裏吧,後面有時間再補充。

版权声明:本文为[喜歡看海的測試小白]所创,转载请带上原文链接,感谢。 https://gsmany.com/2021/08/20210815150253335s.html