使用pytest對接口進行自動化測試

? 上篇博客中講述了什么是接口測試,已經自動化接口測試流程,這篇博客總結如何實現接口自動化測試

(一)requests


requests庫是Python對HTTP通信的一個工具,將http協議操作封裝成簡單的接口,能夠讓我們高效的編寫各種網絡自動化任務

安裝requests庫
我們可以通過pip命令來進行安裝,在控制板中輸入

后面的版本號可以不必一致,可以去官網查看

我們看上面successfully就是安裝成功了
那我們也可以通過另一個命令來查看當前項目有什么庫

接下來我們看如何使用這個庫

首先就是獲取一個http中的get請求到指定url

我們看一下這個方法的參數,url都不陌生就是我們要請求的網址,params就是我們的參數類似于我們在postman中這個位置填的數據
**kwargs是常見可選參數,就比如我們可以在里面設置請求頭,cookie等

使用時只需要調用get接口

傳入對應參數,就會給我們返回一個response對象,該對象包含了服務器給我們返回的一系列信息


當然之前我們學習請求形式不止get請求還有post,put等請求,我們也可以調用對應方法來進行url請求

我們再點進去看他們的源碼

我們發現調用的都是request方法,所以我們想訪問url時,也可以直接調用request方法,只不過需要我們手動去傳入method用什么方式訪問
我們這里舉個實例,我們選擇用一個博客詳情的接口來舉例

其實和我們使用postman類似
但在上面我們傳遞參數發現,可以使用params,json,data來傳參
那么三者有什么區別?

parasms:使用params傳參,參數是在url上體現的傳遞的是簡單的鍵值對,常用于get請求來獲取對應數據,因為可見所以她不適合傳入敏感數據
data:使用data傳參,參數在data中,常用于put或者post請求傳遞的是表單類型的數據,但是data是不支持嵌套的。鍵值對用?&?連接

json:使用json傳參,參數在data中,常用于put或者post請求傳遞的是json的數據,json是支持嵌套的

上面就是request庫的一些操作及使用, requests庫主要是發送http請求,但是對于測試執行和管理就沒怎么涉及到,接下來我們會使用pytest來完成測試的組織,執行,管理功能。


(二)pytest


我們這里選擇使用pytest接口來實現自動化接口測試,除了pytest我們也可使用其他框架比如unnittest或者robot framework等

我們選擇pytest是因為她的語法較為簡單,且插件比較多,我們可以通過下載插件來完成各種功能

pytest的安裝

我們安裝pytest有個版本對應表,不同版本的pytest有最低適配的python版本

下載操作和剛剛我們下載requests操作類似,都是使用pip install操作來下載

同樣我們可以使用pip list來看

安裝好后,我們來看一下有沒有pytest框架對于代碼編寫的區別
有pytest

沒有pytest

我們發現如果沒有pytest框架,我們要執行一個方法,需要一個main函數,并在函數中調用,若我們有了pytest框架,我們可以直接運行該方法,但是我們需要遵守pytest的命名規范,下面就來說一下怎樣命名是可以被pytest識別到的

pytest框架默認命名格則

文件名:文件名需要以test_**來命名或者**_test來命名
測試類:測試類必須以Test開頭,并且不能有__init__方法
測試方法:測試方法必須以test**開頭


init和構造方法


注:測試類中不推薦有init方法(類似于java中的構造方法),但是我們可以定義
之所以不推薦是因為init方法是無法訪問pytest fixtures的(執行順序為:init方法->fixtures->其他方法)
而且構造函數只負責初始化并沒有對應清理機制,且每次測試方法都會創建新的實例。

這一點要做一下區分,此時在pytest中的init方法和構造方法是有很大區別的
就比如我們局一個簡單的例子,我們在python正常類中寫一個init方法和一個類方法,之后我們實例化一個對象并多次調用類方法

我們發現只會調用一次構造函數,在多次調用方法時,也不會再調用構造函數,而當我們在pytest中創建init方法,我們再來看一下

他的輸出是這樣的

init方法在每次測試方法執行前都會重新調用一次(這是因為每個測試方法都是新的實例,測試之間不共享狀態)

以上就是我們為什么不推薦使用init方法,為了處理init方法初始化的作用,pytest給我們提供了其他的初始化方法比如:setup/teardowm或者使用fixture? 這些在之后我們也會再講
注:上面在pytest中使用init方法僅限pytest 4之后的版本,在pytest 4之前版本,是禁止任何類有init方法的

pytest命令參數


pytest提供了很多命令行來控制測試的執行,以下是一些常用的命令航參數以及說明
pytest:在當前目錄和其子目錄下找到符合命名規范的類和方法并運行測試
pytest -v:增加輸出的詳細程序
pytest -s:顯示測試中的print語句
pytest test_module.py :運行指定的測試模塊
pytest test_dir:運行指定目錄下的所有測試
還有一些其他的命令

我們在自己項目中使用pytest命令如下:
會自動執行符合pytest命名規則的方法

但是我們看顯示框,發現信息很少,如果我們要顯示更全面的信息,需要使用-v

但是上面并沒有打印出111,這是因為如果我們想顯示print語句,我們需要-s

當我們想指定測試方法執行時,我們需要手動指定,或者手動點擊
手動指定


我們發現每次要執行指令時,我們要手動輸入很長的一段命令,如何解決這個問題呢?

我們就需要把相關配置參數,統一放到pytest配置文件中

pytest配置文件


需要手動在當前項目下創建pytest.ini文件(文本文件),以下時一些常見的配置選項


在配置文件中我們可以這樣指定

這樣就是說明,我們默認在后面加上-vs,搜索的py文件為test_*,搜索的類為Test*
此時我們執行pytest,我們發現可以自動打印出原來pytest -vs才能執行出的表現

當我們更改搜索的py文件名稱時我們來看看表現


但是同時.ini是不區分大小寫的,如果我們想區分大小寫,我們可以使用yml文件(之后會說)

前后置方法


上面我們說pytest里面不推薦有些版本甚至不能使用init初始化
那如果我們想執行測試用例前后執行一些額外操作,我們就需要用pytest提供的三種額外方法做前后置操作
setup_method和teardown_method:這兩個方法用于類中每個測試方法的前置與后置操作
setup_class和teardowm_class:這兩個方法用于整個測試類的前置和后置操作
fixture:使用fixture是比較推薦到方式,之后會詳細說到fixture的使用

setup_method和teardown_method我們來舉個例子

    def setup_method(self):print("setup method")def teardown_method(self):print("teardown method")def test_01(self):print("True example")def test_02(self):print("True example02")

就比如上述代碼,我們使用setup_method和teardown_method


我們看現象,在測試方法前我們調用setup_method方法,在測試方法后調用teardown_method方法,每個測試方法都會進行一次調用

setup_class和teardown_class我們同樣舉個例子看現象

    def test_01(self):print("True example01")def test_02(self):print("True example02")def setup_class(self):print("setup method")def teardown_class(self):print("teardown method")


我們看到在一個類內,只會調用一次setup/teardown方法

斷言


斷言能夠幫我們檢測程序的狀態是否符合我們的預期,如果斷言失敗,那么python解釋器會給我們拋出一個AssertionError異常,pytest中允許我們使用python中的斷言語句來驗證預期和值

條件必須是一個布爾表達式,錯誤信息選填
這里簡單寫幾個示例

class Test01():#斷言整數a=1b=2assert a==b#斷言字符串s1="str"assert s1=="str"#斷言列表expectList=[1,'aaa',3.21]realList=[1,'aaa',3.21]assert expectList==realList#斷言元組expectTuple=(1,'aaa',3.21)realTuple=(1,'aaa',3.21)assert expectTuple==realTuple#斷言字典expectDict={'a':1,'b':2,'c':3}realDict={'a':1,'b':2,'c':3}assert expectDict==realDict#斷言集合expectSet={'a','b','c'}realSet={'a','b','c'}assert expectSet==realSet

在執行后,我們看到報錯信息還是非常的明顯的,會告訴我們那個斷言錯誤了


這樣我們可以利用斷言來判斷接口的返回值是否符合我們的預期

def test1():url = "http://jsonplaceholder.typicode.com/posts/1"r = requests.get(url=url)expect_data = {"userId": 1,"id": 1,"title": "sunt aut facere repellat provident occaecati excepturi optio
reprehenderit","body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et
cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt
rem eveniet architecto"}print(r.json())assert r.json() == expect_dataassert r.json()['userId'] == 1

如果結果不符合預期就會斷言失敗

參數化


上述的代碼,所有參數都是固定的,那么有沒有一種方式可以像方法一樣傳參,讓過程更加靈活可控呢?

我們可以用pytest內置的pytest.mark.parametrize來對測試函數的參數進行參數化
直接看代碼

 @pytest.mark.parametrize("data",(1,2,3,4,5))def test_01(self,data):print("data: ",data)

? 我們給方法設定一個參數data,然后通過pytest

  @pytest.mark.parametrize("data,result",[(3+5,8),(1+2,3)])def test_01(self,data,result):assert data==result

.mark.parametrize中第一個參數為要傳的參數,第二個為參數的值

我們不止可以設定一個參數,也可以設置多個參數
代碼如下:



此外除了可以在方法上使用這個參數化之外,在類上同樣可以使用參數化

@pytest.mark.parametrize("data,result", [(3 + 5, 8), (1 + 2, 3)])
class Test01():def test_01(self, data, result):assert data == resultdef test_02(self, data, result):print(data,result)

現象如下,我們發現都會執行到

此時可能就會有疑問,當我們設定了同樣的參數在類和方法上,會發生什么?可以來執行看下

@pytest.mark.parametrize("data,result", [(3 + 5, 8), (1 + 2, 3)])
class Test01():def test_01(self, data, result):assert data == result@pytest.mark.parametrize("data,result", [(1 + 5, 6), (2 + 2, 4)])def test_02(self, data, result):print(data,result)


上述告訴我們多次嘗試對同一個參數進行重復參數化問題,解決辦法也很簡單
1.我們可以把類層和方法層參數合并到同一個層級
2.類層和方法層使用不同的參數名
除了可以手動指定參數外,我們也可以使用方法返回值來當作參數,只需要把手動指定參數的地方換成函數調用即可,類似于這樣

注:當我們設定了參數化找不到對應參數時,是會報錯的


fixture

用來提供測試函數所需要的資源或者上下文,有點類似于AOP面向切面編程的思想
以下是fixture的一些概念及使用場景
我們來看fixture的基礎使用

class Test01():def fixture01(self):print("fixture1111")def test02(self):Test01.fixture01(self)print("test02")
class Test01():@pytest.fixture()def fixture01(self):print("fixture1111")def test02(self,fixture01):#    Test01.fixture01(self)print("test02")

我們看上述兩個代碼,第一種是在第二個方法中調用第一個方法
而第二種方法,是直接將函數名作為參數進行調用
我們看結果都是一樣的

當然也可以在第一種的fixture方法上加上注解,也可以正常使用
那傳到參數和方法中調用有什么區別呢?


除了基本使用fixture,也可以嵌套的使用fixture

class Test01():@pytest.fixture()def fixture01(self):return "01"@pytest.fixture()def est02(self,fixture01):#    Test01.fixture01(self)return fixture01def test03(self, est02):#    Test01.fixture01(self)print(est02)

與函數嵌套很類似

不止嵌套,我們同樣可以在參數列表中調用多個fixture注解修飾的函數

class Test01():@pytest.fixture()def fixture01(self):return "01"@pytest.fixture()def est02(self,fixture01):#    Test01.fixture01(self)return "010203"def test03(self, fixture01,est02):#    Test01.fixture01(self)assert fixture01 in est02



fixture不止傳參提供資源這一個用處,之前說過它可以用作于上下文
此時我們需要在代碼中加上yield,這個主要是為了在我們運行測試時,確保它能夠正確的自我清理,以便他不會干擾到其他的測試
我們使用yield而不是return,這樣我們可以運行一些代碼后,把對象返回給其他請求方法
但與return不同的是,該fixture的任何拆解代碼要放在yield之后
一旦pytest確定了fixture,他會運行所有的fixture知道返回或者yield,然后執行下一個fixture重復此工作
測試完成后,pytest會逆向遍歷fixture,對于每個yield后的fixture,運行yield語句之后的代碼

class Test01():@pytest.fixture()def fixture01(self):print("start")yieldprint("stop")def test03(self, fixture01):#    Test01.fixture01(self)print("test03")

我們預期的表現是先打印對應方法中調用的fixture在yield前的代碼,然后執行函數體,最后執行yield后的代碼,看現象

帶參數的fixture
看下這個注解的源碼,我們看到有很多參數,但是我們上面在使用時,暫時沒涉及到,這里來講一下參數都有什么用


scope:
function:每個測試函數會調用fixture(也是默認的值)
class:在同一個測試類中共享這個fixture

class Test01():@pytest.fixture(scope="class")def fixture01(self):print("start")yieldprint("stop")def test05(self):#    Test01.fixture01(self)print("test03")def test03(self, fixture01):#    Test01.fixture01(self)print("test03")def test04(self):#    Test01.fixture01(self)print("test04")

按順序先執行test05方法,因不涉及到fixture方法所以還沒有調用,到了test03,先執行fixture方法中yield前的部分,等到class結束后執行yield后的部分
module:在一個文件里共享這個fixture
session:整個測試會話中共享這個fixture

autouse:默認參數為false,代表我們需要顯示傳入,才會調用,如果設置為true,就代表每個測試函數都會自動的調用fixture
params:用于參數化,fixture支持列表,每個參數都會讓fixture執行一次,類似for循環
ids:與params搭配使用,為每個參數化實例指定標識符
類似這樣

@pytest.fixture(params=[1, 2, 3],ids=["測試值1", "測試值2", "測試值3"]
)
def number(request):return request.param

name:用來給fixture方法設定一個名稱,如果使用name,則在測試函數中需要使用這個名稱來引用fixture


剩下的命令,下一篇再說

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/918229.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/918229.shtml
英文地址,請注明出處:http://en.pswp.cn/news/918229.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

信息安全及防火墻總結

1.1 信息安全現狀及挑戰信息安全概述 信息安全:防止任何對數據進行未授權訪問的措施,或者防止造成信息有意無意泄漏、破壞、 丟失等問題的發生,讓數據處于遠離危險、免于威脅的狀態或特性。 網絡安全:計算機網絡環境下的信息安全。…

20250808組題總結

A - A Pak Chanek 有一個包含 nnn 個正整數的數組aaa。由于他正在學習如何計算兩個數字的向下取整平均值,他希望在他的數組 aaa 上進行練習。當數組 aaa 至少有兩個元素時,Pak Chanek 將執行以下三步操作: ?\bullet?選擇兩個不同的索引 ii…

【Python 語法糖小火鍋 · 第 5 涮 · 完結】

一、糖味一句話 Python 3.10 的 match-case 把「類型 值 嵌套」一次性拆開, 可讀性 10,bug 數 10,if-elif 可以安心退休了。二、1 行示例 3 連發 # ① 值匹配 match status:case 200: msg "ok"case 404: msg "not found&q…

寫 SPSS文件系統

寫入 SPSS 系統文件(.sav、.zsav) 以下為相關的 SPSS 命令(以大寫形式 CAPS 呈現) savFileName : str SPSS 數據文件的文件名 以 .sav 結尾的文件使用舊版壓縮方案壓縮。 以 _uncompressed.sav 結尾的文件不壓縮,這在需…

云服務器--阿里云OSS(1)【阿里云OSS簡單介紹以及環境準備】

一、阿里云OSS簡介 定義:阿里云OSS(Object Storage Service)是阿里云提供的對象存儲服務,支持海量數據的存儲和管理。 存儲方式:基于“對象存儲”,文件以對象形式存儲,無需管理文件系統結構。 …

R語言代碼加密(1)

1、使用Compiler包library(compiler) cmpfile("1.R")#實現對R腳本的整體加密 compiler::loadcmp("1.Rc")#調用R腳本存在問題是,該方法僅對腳本進行加密。在加載生成的Rc文件后,腳本內具體函數,是可以看到具體內容的。針對…

【面試場景題】通過LinkedHashMap來實現LRU與LFU

文章目錄一、LRU與LFU的概念1. LRU(Least Recently Used,最近最少使用)2. LFU(Least Frequently Used,最不經常使用)二、LinkedHashMap的特性三、用LinkedHashMap實現LRU實現代碼:原理說明&…

第5章 Excel公式與函數應用指南(2):數學函數

5.2 數學函數 Excel作為強大的數據處理工具,其內置的數學函數體系為用戶提供了豐富的計算能力。從基礎的四則運算到復雜的指數對數計算,從簡單的數值舍入到專業的矩陣運算,Excel的數學函數幾乎可以滿足各類計算需求。 本節將重點為您解析七個常用且實用的數學函數:求和函…

mysql復制連接下的所有表+一次性拷貝到自己的庫

1.導出鏈接下的所有數據mysqldump -h 地址 -u 數據庫名 -p --all-databases --single-transaction --master-data2 > all_dbs.sql2.導入自己的庫mysql -h 127.0.0.1 -u root -p < all_dbs.sql3.指定導出某些庫mysqldump -u root -p --databases db1 db2 db3 > /path/t…

開發手札:UnrealEngine和Unity3d坐標系問題

最近把一套網絡模塊和一套組件模塊從u3d改造到ue4。網絡模塊通用性很高&#xff0c;畢竟協議都是通用網絡協議&#xff0c;改造后沒啥問題。但是改造組件模塊的時候就遇到了問題。首先&#xff0c;unity3d的坐標系是標準左手坐標系&#xff0c;如下&#xff1a;同時自己的幾何算…

QML 鼠標穿透

事件&#xff1a; 有一個輸入框(TextField)&#xff0c;需要實現鼠標懸浮時改變邊框顏色&#xff0c;鼠標移出后恢復原來邊框顏色&#xff1b; 這時如果需要實現此功能&#xff0c;就得使用到MouseArea&#xff0c;鼠標操作區域填充滿整個TextField。 然后實現鼠標移入移入出的…

VR 設備 PCB 怎樣憑借高頻材料達成高速傳輸

VR 設備的沉浸式體驗依賴于高分辨率圖像與低延遲交互&#xff0c;這要求設備內部數據傳輸速率達到 10Gbps 以上&#xff0c;而印制線路板&#xff08;PCB&#xff09;作為信號傳輸的核心載體&#xff0c;其材料性能直接決定傳輸效率。高頻材料憑借低介電常數&#xff08;Dk&…

Oracle字段操作

1. 新增字段 -- 新增字段 ALTER TABLE MES.WT_SUPPLEMENT_RECORD ADD (PAR_ATTR3 NUMBER DEFAULT NULL);2. 修改字段類型 -- 修改字段類型 ALTER TABLE MES.WT_SUPPLEMENT_RECORD MODIFY (PAR_ATTR3 VARCHAR2(32));3. 刪除字段 -- 刪除字段 ALTER TABLE MES.WT_SUPPLEMENT_RECO…

【原創】基于 Flask 的簡單文件收集器

在單位內網環境中&#xff0c;我經常需要收集 pdf 格式的記錄表。于是我基于 ai ide&#xff0c;開發了一個基于 Flask 開發的輕量級文件上傳服務項目&#xff0c;部署在單位飛騰芯的銀河麒麟系統上&#xff08;當然由于 python 的跨平臺&#xff0c;在 windows 和 mac 上也可部…

學習Java的Day28

今天在昨天完成的留言板項目基礎上&#xff0c;我進一步開發了一個酒店房型管理系統。該系統采用MVC架構&#xff0c;主要功能是對酒店房型信息進行增刪改查操作。數據庫設計方面&#xff0c;我創建了hotel_room_type表&#xff0c;包含以下字段&#xff1a;id&#xff1a;主鍵…

Leetcode——556. 下一個更大元素 III

題目鏈接&#xff1a;556. 下一個更大元素 III &#xff08;由于圖片上傳失敗&#xff0c;不貼原題目了&#xff0c;有需要可以前往力扣查看&#xff09; 本文給出該題的單調棧做法&#xff0c;同時繞過所有庫函數&#xff0c;所有邏輯均自行實現。 本題的思路就是從右向左按…

Idea打包可執行jar,MANIFEST.MF文件沒有Main-Class屬性:找不到或無法加載主類

背景&#xff1a;IDEA傳統方法【Project structure】-->artifact---->build的模式&#xff0c;打包【Maven】項目&#xff0c;發現生成的可執行jar包&#xff0c;顯示【找不到或無法加載主類】。但是用【Maven】的Assembly可以正常生成。期望用傳統方法實現打jar包方法&a…

檢索增強生成:RAG(Retrieval Augmented Generation)

什么是 RAG&#xff1f;為什么使用 RAG&#xff1f;LLM 微調 和 RAG&#xff1f;實戰什么是 RAG&#xff1f; RAG 在論文《Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks》中被引入&#xff0c;原論文是這樣描述的&#xff1a; 探索了一種 通用的 檢索增…

Android 設置/修改系統NTP服務地址

Android 手機的 NTP 時間同步&#xff08;網絡時間同步&#xff09;主要依賴網絡&#xff0c;但系統時間來源還包括其他方式&#xff0c;整體時間校準機制是多種來源的結合。具體可分為以下幾類&#xff1a; 1. 網絡 NTP 同步&#xff08;最主要方式&#xff09; 這是 Androi…

Ubuntu22.04 安裝vitis2023.2 卡在“Generating installed device list“.

關于這個問題&#xff0c;xilinx有官方說明&#xff0c;鏈接 原因&#xff1a;問題是 Ubuntu 20.04 缺少 libtinfo.so.5 庫。 解決辦法&#xff1a; sudo apt-get install libtinfo5