欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

使用python+requests+pytest實現(xiàn)接口自動化

 更新時間:2023年08月15日 10:10:55   作者:愛吃 香菜  
這篇文章主要介紹了使用python+requests+pytest實現(xiàn)接口自動化,在當(dāng)前互聯(lián)網(wǎng)產(chǎn)品迭代頻繁的背景下,回歸測試的時間越來越少,但接口自動化測試因其實現(xiàn)簡單、維護成本低,容易提高覆蓋率等特點,越來越受重視,需要的朋友可以參考下

主要思路:

  1. 對 requests 進行二次封裝,做到定制化效果
  2. 使用 excel 存放接口請求數(shù)據(jù),作為數(shù)據(jù)驅(qū)動
  3. 里面有一些功能模仿了 jmeter,比如用戶參數(shù)定義、jsonpath 提取
  4. 用 pytest 進行測試用例管理

一、環(huán)境

  • python==3.8.0
  • requests==2.31.0
  • pytest==7.4
  • 還有一些其他第三方庫例如 allure 報告、jsonpath 等

這塊不過多介紹,安裝 python 配置環(huán)境變量,pip install 命令安裝所需插件即可

二、項目目錄結(jié)構(gòu)

圖片

1、config用來存放項目配置文件,包括接口基礎(chǔ)配置,數(shù)據(jù)庫信息等,使用的是 configparser 進行讀取

圖片

2、Outputs 層存放了日志和測試報告,這里報告用的是 allure

圖片

圖片

3、resources 存放的是測試數(shù)據(jù) (這里用的 excel 作為接口數(shù)據(jù)驅(qū)動) 以及其他的一些測試文件等

4、Testcases 存放測試類

5、utils:工具類,包含了讀取配置、記錄日志、http 請求、接口數(shù)據(jù)處理等功能

三、重點功能介紹

1、讀取 excel

實現(xiàn)代碼如下:

from openpyxl import load_workbookclass DoExcel:
   def __init__(self, file_name):  
       # 打開文件        self.filepath = os.path.join(resources,'case_datas', f'{file_name}.xlsx')
       # 獲取工作表        self.wb = load_workbook(self.filepath)
       # 獲取當(dāng)前sheet        self.ws = self.wb.active
   def get_data_from_excel(self):
       '''從excel獲取測試數(shù)據(jù)'''
       datas = []
       for row in range(1, self.ws.max_row + 1):
           row_data = {}
           if row > 1:
               # 將行數(shù)據(jù)轉(zhuǎn)為字典數(shù)據(jù)格式                for column in range(1, self.ws.max_column + 1):
                   row_data[f"{self.ws.cell(1, column).value}"] = self.ws.cell(row, column).value
               # 將json_path轉(zhuǎn)字典                if row_data["json_path"]:
                   row_data["json_path"] = {k: v for item in row_data["json_path"].split("&") for k, v in[item.split("=")]}
               datas.append(row_data)
       self.wb.close()
       return datas
   def close(self):
       # 關(guān)閉文件流        self.wb.close()

數(shù)據(jù)文檔格式:

圖片

(這里目前只支持單 sheet 頁讀取,后續(xù)將擴展成 sheet 名稱傳參獲取方式)

2、requests 請求部分

import requestsclass HttpRequest:
   def __init__(self):
       self.session = requests.sessions.session()
       self.global_headers = {"X-Request-Sign": "xxxxxxxxx"}
   def set_headers(self, path, content_type, headers):
       # 判斷接口是登錄時,將Authorization請求頭刪除        if path in ["oauth/oauth/userlogin", "/oauth/oauth/login"] and "Authorization" in self.global_headers.keys():
           self.global_headers.pop("Authorization")
       # 判斷content_type為json時,添加請求頭content_type        if content_type == "json":
           self.global_headers["Content-Type"] = "application/json;charset=UTF-8"
       # 判斷content_type不為json時,刪除請求頭content_type        elif content_type != "json" and "Content-Type" in self.global_headers.keys():
           self.global_headers.pop("Content-Type")
       # 將接口信息中的請求頭更新到global_headers中        if headers:
           self.global_headers.update(headers)
   def set_token(self, path, res_code, res_json):
       # 請求接口為登錄并且返回成功時,將token附加到headers里        if path == "/oauth/oauth/login" and res_code == 200:
           token = json_path(res_json, "$.data.access_token")
           self.global_headers["Authorization"] = f"Bearer {token}"
   def clear_headers(self, headers):
       # 清除無用的請求頭        if headers:
           for i in headers.keys():
               if i in self.global_headers.keys():
                   self.global_headers.pop(i)
   def http_request(self, datas, file=None):
       log_info.log_info('--------------------')
       log_info.log_info('↓↓↓↓↓接口請求開始↓↓↓↓↓')
       # 拼接url  base從配置文件獲取+參數(shù)傳遞接口路徑        urls = config.get_strValue('api', 'base_url') + datas["path"]
       self.set_headers(path=datas["path"], content_type=datas["content_type"], headers=datas["headers"])
       log_info.log_info(f'接口名稱:{datas["desc"]}')
       log_info.log_info(f"請求地址:{urls}")
       log_info.log_info(f"請求頭:{self.global_headers}")
       log_info.log_info(f'請求參數(shù):{datas["params"]}')
       print((f"請求地址:{urls}"))
       res = None
       # 請求封裝,這里用的session會話保持,https請求需要將verify設(shè)置為False        try:
           if datas["method"].lower() == 'get':
               res = self.session.request(datas["method"], urls, params=datas["params"], headers=self.global_headers,
                                          verify=False)
           elif datas["method"].lower() == 'post':
               if datas["content_type"] in ["form", "upload"]:
                   res = self.session.request(datas["method"], urls, data=datas["params"], headers=self.global_headers,
                                              files=file,verify=False)
               elif datas["content_type"] == "json":
                   res = self.session.request(datas["method"], urls, json=datas["params"], headers=self.global_headers,
                                              verify=False)
           log_info.log_info(f"響應(yīng)信息:{res.text}")
       except Exception as e:
           log_info.log_info(e)
           raise e
       self.set_token(path=datas["path"], res_code=res.status_code, res_json=res.json())
       self.clear_headers(headers=datas["headers"])
       log_info.log_info('↑↑↑↑↑接口請求結(jié)束↑↑↑↑↑')
       log_info.log_info('--------------------')
       return res
   def close(self):
       self.session.close()

在這里我根據(jù)項目情況,進行了請求頭的特殊處理;

  1. 實例化對象的時候添加了全局請求頭
  2. 根據(jù)不同類型的請求和傳參格式對 content-type 做了相應(yīng)處理
  3. token 的處理
  4. 最后請求后把當(dāng)前無用請求頭部分做了清理

3、接口數(shù)據(jù)處理

class DataHandle:
   def datas_init(self,datas,params_list):
       self.datas = datas
       self.params_list = params_list
   def headers_handle(self):
       # 將請求頭進行參數(shù)化        if self.datas["headers"]:
           self.datas["headers"] = re_replace(self.datas["headers"], self.params_list)
       # 請求頭轉(zhuǎn)字典格式        if self.datas["headers"]:
           self.datas["headers"] = {k: v for item in self.datas["headers"].split("&") for k, v in [item.split("=", 1)]}
       return self.datas["headers"]
   def params_handle(self):
       # 將請求參數(shù)進行參數(shù)化        if self.datas["params"]:
           self.datas["params"] = re_replace(self.datas["params"], self.params_list)
       # 這里把請求參數(shù)格式化,轉(zhuǎn)成不同方法需要的參數(shù)格式        # 將form表單格式的參數(shù)轉(zhuǎn)化成字典        if self.datas["content_type"] in ["form","upload"] and self.datas["params"]:
           self.datas["params"] = {k: v for item in self.datas["params"].split("&") for k, v in [item.split("=")]}
       # 將json字符串解包為字典        elif self.datas["content_type"] == "json":
           self.datas["params"] = eval(self.datas["params"])
       return self.datas["params"]
   def user_var_handle(self,res):
       # 獲取響應(yīng)信息中下文接口用到的參數(shù)        if self.datas["json_path"]:
           for i in self.datas["json_path"].keys():
               self.params_list[i] = json_path(res.json(), self.datas["json_path"][i])
       return self.params_list
   def assert_handle(self,res):
       # 將預(yù)期結(jié)果處理        if self.datas["except"]:
           # 參數(shù)化替換            self.datas["except"] = re_replace(self.datas["except"], self.params_list)
           # 轉(zhuǎn)成字符串列表            self.datas["except"] = self.datas["except"].split("&")
       # 斷言        for i in self.datas["except"]:
           print(f"斷言:{i}")
           assert i in res.text
   def send_request(self,datas,file=None):
       res = http_request.http_request(datas,file)
       return res

這里主要做了幾點處理:

  1. 將請求頭部分做了參數(shù)化替換并進行了數(shù)據(jù)格式轉(zhuǎn)換,轉(zhuǎn)為字典格式
  2. 請求 body 進行參數(shù)化,并根據(jù)請求方式和 content-type 做了相應(yīng)處理
  3. 用戶參數(shù)處理,用 jsonpath 獲取響應(yīng)信息字段值存放到測試類屬性中
  4. 預(yù)期結(jié)果斷言處理(這里統(tǒng)一用的自帶的 assert 方法,還沒進行二次封裝)
  5. 將更新后的 data 發(fā)送請求

4、測試類,測試方法

class TestDemo(DataHandle):
   params_list = {'custName': unique_string(), "custCertiNo": random_string(),
                  "custLegalPersonCertiNo": random_string(18), "custBankAccount": random_string(18),
                  "managerStamp":{"file": ("testpicture.png", open(upload_file + "\\" + "testpicture.png", "rb"), "image/png")}
                  }
   @ pytest.mark.usefixtures("login_guanliren")
   @ pytest.mark.parametrize("datas", DoExcel("demo").get_data_from_excel())
   def test_case(self, datas):
       # 數(shù)據(jù)初始化        self.datas_init(datas, self.params_list)
       # 請求頭處理        datas["headers"] = self.headers_handle()
       # 請求參數(shù)處理        datas["params"] = self.params_handle()
       # 獲取文件名        filename = datas["filename"]
       # 發(fā)送接口請求        res = self.send_request(datas=datas,file=self.params_list[filename] if datas["content_type"] == "upload" else None)
       # 參數(shù)列表處理        self.params_list = self.user_var_handle(res)
       # 預(yù)期結(jié)果及斷言        self.assert_handle(res)

這里測試類繼承了上面的 DataHandle 類,測試方法中可以調(diào)用父類方法進行測試數(shù)據(jù)的處理 params_list 是用字典存放的參數(shù)化的數(shù)據(jù),我這里是通過正則替換把請求參數(shù)里面的需要被替換的部分找到 params_list 里的 key,將 value 進行替換

5、runner 執(zhí)行測試用例

import pytestfrom project.utils.base_dir import *if __name__ == '__main__':
   pytest.main(['-vs', f'{test_class}', f'--alluredir={allure_dir} ', '--clean-alluredir'])
   os.system(f"allure generate {allure_dir} -o {allure_html} --clean")

調(diào)用 pytest 的 main 方法進行命令行參數(shù)執(zhí)行,添加了 allure 生成測試報告

圖片

6、測試報告展示

圖片

圖片

7、未完成功能

  1. excel 讀?。含F(xiàn)在只支持當(dāng)前 sheet 頁讀取,后續(xù)擴展成傳 sheet 名稱指定獲取
  2. 數(shù)據(jù)庫斷言:excel 添加一列存放 sql 語句,發(fā)送接口請求后查詢數(shù)據(jù)庫,將這部分加進斷言里
  3. http_requests 目前只有 get 和 post 方法,后續(xù)將其他方法也封裝進去
  4. 斷言方式:目前沒有對斷言封裝,用的自帶的 assert 函數(shù),后面可以進行二次封裝或用第三方庫實現(xiàn)

到此這篇關(guān)于使用python+requests+pytest實現(xiàn)接口自動化的文章就介紹到這了,更多相關(guān)python實現(xiàn)接口自動化內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論