軟件測試 | pytest測試框架
pytest 是一個全功能的 Python 測試工具,可以幫助您編寫更好的程序。它與 Python 自帶的 unittest 測 試框架類似,但 pytest 使用起來更簡潔和高效,并且兼容 unittest 框架。pytest 支持簡單的單元測試和 復(fù)雜的功能測試,可以結(jié)合 requests 實現(xiàn)接口測試,結(jié)合 selenium、appium 實現(xiàn)自動化功能測試,使 用 pytest 結(jié)合 Allure2 集成到 Jenkins 中可以實現(xiàn)持續(xù)集成。pytest 支持三百多種插件(可以訪問網(wǎng) 址:http://plugincompat.herokuapp.com/?查看插件),可以訪問網(wǎng)址:https://docs.pytest.org/?查看幫助文 檔。
安裝
查看版本
pytest --version
用例的識別與運行
用例編寫規(guī)范
測試文件以 test_開頭或以 _test 結(jié)尾
測試類以 Test 開頭,并且不能帶有 __init__ 方法
測試函數(shù)以 test_開頭
斷言使用基本的 assert 即可
創(chuàng)建一個 python 文件,命名以 test_ 開頭(或者以 _test 結(jié)尾),創(chuàng)建測試方法以 test_ 開 頭,測試類需要以 Test 開頭。
創(chuàng)建文件名為 test_add.py 文件,代碼如下:
命令行進入到這個文件所在的路徑,運行 test_add.py 文件。
可以直接使用 pytest 命令運行,pytest 會找當(dāng)前目錄以及遞歸查找子目錄下所有的 test_*.py 或 *_test.py 的文件,把其當(dāng)作測試文件。在這些文件里,pytest 會收集符合編寫規(guī)范的函數(shù)、類以及 方法,當(dāng)作測試用例并且執(zhí)行。
執(zhí)行如下:
結(jié)果分析:
執(zhí)行結(jié)果中, F 代表用例未通過(斷言錯誤), . 代表用例通過。如果報錯會有詳細的錯誤信息。 pytest 也支持運行 unittest 模式的用例。
運行參數(shù)
pytest 提供了很多參數(shù),可以使用 pytest --help 來查看幫助文檔,下面介紹幾種常用的參數(shù):
打印詳細運行日志信息,一般在調(diào)試的時候加上這個參數(shù),終端會打印出每條用例的詳細日志信息,方 便定位問題。使用方法如下:
-k 參數(shù)
只執(zhí)行含有某個關(guān)鍵字的測試用例。
控制臺輸出結(jié)果,當(dāng)你的代碼里面有 print 輸出語句,如果想在運行結(jié)果中打印 print 輸出的代碼 (默認控制臺是不輸出打印結(jié)果的),在運行的時候可以添加 -s 參數(shù),一般在調(diào)試的時候使用,使 用方法如下:
注意:如果是 windows 系統(tǒng), -k 后面的字符串參數(shù)必須用雙引號。
-x 參數(shù)
遇到用例失敗立即停止運行。
應(yīng)用場景:
在回歸測試過程中,假如一共有 10 條基礎(chǔ)用例,當(dāng)開發(fā)人員打完包提交測試的時候,需要先運行這 10 條基礎(chǔ)用例,全部通過才能提交給測試人員正式測試。如果有一條用例失敗,就將這個版本打回給 開發(fā)人員。這時就可以添加 -x 參數(shù),一旦發(fā)現(xiàn)有失敗的用例即中止運行。
使用方法如下:
--maxfail 參數(shù)
用例失敗個數(shù)達到閾值停止運行。 應(yīng)用場景: 在回歸測試過程中,假如一共有 10 條基礎(chǔ)用例,當(dāng)開發(fā)人員打完包提交測試的時候,需要先運行這 10 條基礎(chǔ)用例,全部通過才能提交給測試人員正式測試。如果運行過程中有 [num] 條用例失敗,即 中止運行,后面測試用例都放棄執(zhí)行,直接退出。這時可以使用 --maxfail 參數(shù)。
具體用法:
-m參數(shù)
將運行有 @pytest.mark.[標記名] 這個標記的測試用例。
應(yīng)用場景:
在自動化測試過程中可以將測試用例添加標簽進行分類,比如登錄功能、搜索功能、購物車功能、訂單 結(jié)算功能等,在運行的時候可以只運行某個功能的所有的測試用例,比如這個版本只想驗證登錄功能, 那就在所有登錄功能的測試用例方法上面加上裝飾符 @pytest.mark.login ,運行的時候使用命令添 加一個 -m 參數(shù),例如執(zhí)行 pytest -m login 命令就可以只執(zhí)行登錄功能這部分的測試用例。
使用方法如下:
運行模式
pytest 提供了多種運行模式,讓開發(fā)和調(diào)試更得心應(yīng)手。指定某個模塊,執(zhí)行單獨一個 pytest 模塊。
應(yīng)用場景:
在編寫測試用例的時候,經(jīng)常會單獨調(diào)試某個類,或者某個方法,這時可以使用 Pycharm 里面自帶的調(diào) 試方式,點擊用例方法名前面的綠色按鈕,也可以使用命令行的方式單獨運行某個用例。
pytest 中可以使用 pytest 文件名.py 單獨執(zhí)行某個 python 文件,也可以使用 pytest 文件名.py:: 類名 單獨執(zhí)行某個文件中的類,使用 pytest 文件名.py::類名::方法名 單獨執(zhí)行類中的某個方法。 使用方法如下:
在Pycharm中運行pytest用例

打開 Pycharm -> 設(shè)置 - Tools -> Python Integrated Tools -> Testing: pytest
首先設(shè)置成 pytest ,需要安裝 pytest,可以直接按照這個頁面的提示點擊 fix ,也可以在 Project interpreter 里面添加 pytest 安裝包。安裝完 pytest 之后,符合規(guī)則的測試用例都能被識別出來并且會顯 示出一個三角形的執(zhí)行按鈕,點擊這個按鈕也能執(zhí)行某個方法或者某個類。例如:
pytest 框架結(jié)構(gòu)
執(zhí)行用例前后會執(zhí)行 setup,teardown 來完成用例的前置和后置條件。pytest 框架中使用 setup, teardown 更靈活,按照用例運行級別可以分為以下幾類:
模塊級(setup_module/teardown_module)在模塊始末調(diào)用
函數(shù)級(setup_function/teardown_function)在函數(shù)始末調(diào)用(在類外部)
類級(setup_class/teardown_class)在類始末調(diào)用(在類中)
方法級(setup_method/teardown_methond)在方法始末調(diào)用(在類中)
方法級(setup/teardown)在方法始末調(diào)用(在類中)
調(diào)用順序
setup_module > setup_class >setup_method > setup > teardown > teardown_method > teardown_class > teardown_module
畫圖說明

驗證上面的執(zhí)行順序,看下面的案例。
創(chuàng)建文件名為 test_module.py ,代碼如下:
運行結(jié)果:
setup_module 和 teardown_module 在整個模塊只執(zhí)行一次,setup_class 和 teardown_class 在類里面只 執(zhí)行一次,setup_method/setup 和 teardown_method/teardown 在每個方法前后都會調(diào)用。一般用的最多 的是方法級別(setup/teardown)和類級別(setup_class/teardown_class)。
pytest fixtures
pytest 中可以使用 @pytest.fixture 裝飾器來裝飾一個方法,被裝飾的方法名可以作為一個參數(shù)傳入 到測試方法中??梢允褂眠@種方式來完成測試之前的初始化,也可以返回數(shù)據(jù)給測試函數(shù)。
將 FIXTURE 作為函數(shù)參數(shù)
通常使用 setup 和 teardown 來進行資源的初始化。如果有這樣一個場景,測試用例 1 和 測試用例 3 需要依賴登錄功能,測試用例 2 不需要依賴登錄功能。這種場景 setup,teardown 無法實現(xiàn),可以使用 pytest fixture 功能,在方法前面加個 @pytest.fixture 裝飾器,加了這個裝飾器的方法可以以參數(shù)的 形式傳入到方法里面執(zhí)行。例如在登錄的方法,加上 @pytest.fixture 這個裝飾器后,將這個用例 方法名以參數(shù)的形式傳到方法里,這個方法就會先執(zhí)行這個登錄方法,再去執(zhí)行自身的用例步驟,如果 沒有傳入這個登錄方法,就不執(zhí)行登錄操作,直接執(zhí)行已有的步驟。
創(chuàng)建一個文件名為 “test_fixture.py”,代碼如下;
在上面的代碼中,測試用例 test_case1 和 test_case3 分別增加了 login 方法名作為參數(shù),pytest 會發(fā)現(xiàn) 并調(diào)用 @pytest.fixture 標記的 login 功能,運行測試結(jié)果如下:
從上面的結(jié)果可以看出,test_case1 和 test_case3 運行之前執(zhí)行了 login 方法,test_case2 沒有執(zhí)行這個 方法。
指定范圍內(nèi)共享
fixture 里面有一個參數(shù) scope,通過 scope 可以控制 fixture 的作用范圍,根據(jù)作用范圍大小劃分: session> module> class> function,具體作用范圍如下:
例如整個模塊有很多條測試用例,需要在全部用例執(zhí)行之前打開瀏覽器,全部執(zhí)行完之后去關(guān)閉瀏覽 器,打開和關(guān)閉操作只執(zhí)行一次,如果每次都重新執(zhí)行打開操作,會非常占用系統(tǒng)資源。這種場景除了 setup_module/teardown_module 可以實現(xiàn),還可以通過設(shè)置模塊級別的 fixture 裝飾器 (@pytest.fixture(scope="module"))來實現(xiàn)。
scope='module'
fixture 參數(shù) scope='module' ,module 作用是整個模塊都會生效。
創(chuàng)建文件名為 test_fixture_scope.py ,代碼如下:
代碼解析:
@pytest.fixture() 如果不寫參數(shù),參數(shù)默認 scope='function' 。當(dāng) scope='module' 時,在當(dāng)前 .py 腳本里面所有的用例開始前只執(zhí)行一次。scope 巧妙與 yield 關(guān)鍵字結(jié)合使用,相當(dāng)于 setup 和 teardown 方法。還可以使用 @pytest.mark.usefixtures 裝飾器,傳入前置函數(shù)名作為參數(shù)。
運行結(jié)果如下:
從上面運行結(jié)果可以看出, scope="module" 與 yield 結(jié)合,相當(dāng)于 setup_module 和 teardown_module 方法。整個模塊運行之前調(diào)用了 open() 方法中 yield 前面的打印輸出“打開瀏覽 器”,整個運行之后調(diào)用了 yield 后面的打印語句“執(zhí)行 teardown !”與“關(guān)閉瀏覽器”。
通過 yield 來喚醒 teardown 的執(zhí)行,如果用例出現(xiàn)異常,不影響 yield 后面的 teardown 執(zhí)行。
CONFTEST.PY 文件
fixture scope 為 session 級別是可以跨 .py 模塊調(diào)用的,也就是當(dāng)我們有多個 .py 文件的用例時, 如果多個用例只需調(diào)用一次 fixture,可以將 scope='session' ,并且寫到 conftest.py 文件里。 寫到 conftest.py 文件可以全局調(diào)用這里面的方法。使用的時候不需要導(dǎo)入 conftest.py 這個文 件。使用 conftest.py 的規(guī)則:
1. conftest.py 這個文件名是固定的,不可以更改。
2. conftest.py 與運行用例在同一個包下,并且該包中有 __init__.py 文件
3.使用的時候不需要導(dǎo)入 conftest.py ,pytest 會自動識別到這個文件
4.放到項目的根目錄下可以全局調(diào)用,放到某個 package 下,就在這個 package 內(nèi)有效。
案例
運行整個項目下的所有的用例,只執(zhí)行一次打開瀏覽器。執(zhí)行完所有的用例之后再執(zhí)行關(guān)閉瀏覽器,可 以在這個項目下創(chuàng)建一個 conftest.py 文件,將打開瀏覽器操作的方法放在這個文件下,并添加一個 裝飾器 @pytest.fixture(scope="session") ,就能夠?qū)崿F(xiàn)整個項目所有測試用例的瀏覽器復(fù)用,案 例目錄結(jié)構(gòu)如下:

創(chuàng)建目錄 test_scope,并在目錄下創(chuàng)建三個文件 conftest.py , test_scope1.py 和 test_scope2.py 。 conftest.py 文件定義了公共方法,pytest 會自動讀取 conftest.py 定義的方法,代碼如下:
創(chuàng)建“test_scopel.py”文件,代碼如下:
創(chuàng)建文件“test_scope2.py”,代碼如下:
打開 cmd,進入目錄 test_scope/,執(zhí)行如下命令:
或者
執(zhí)行結(jié)果如下:
自動執(zhí)行FIXTURE
如果每條測試用例都需要添加 fixture 功能,則需要在每一條要用例方法里面?zhèn)魅脒@個 fixture 的名字, 這里就可以在裝飾器里面添加一個參數(shù) autouse='true' ,它會自動應(yīng)用到所有的測試方法中,只是這 里沒有返回值。 使用方法,在方法前面加上裝飾器,如下:
@pytest.fixture 里設(shè)置 autouse 參數(shù)值為 true(默認 false),每個測試函數(shù)都會自動調(diào)用這個前置 函數(shù)。 創(chuàng)建文件名為“test_autouse.py”,代碼如下:
執(zhí)行上面這個測試文件,結(jié)果如下:
從上面的運行結(jié)果可以看出,在方法 myfixture() 上面添加了裝飾器 @pytest.fixture(autouse="true") ,測試用例無須傳入這個 fixture 的名字,它會自動在每條用例 前執(zhí)行這個 fixture。
FIXTURE 傳遞參數(shù)
測試過程中需要大量的測試數(shù)據(jù),如果每條測試數(shù)據(jù)都編寫一條測試用例,用例數(shù)量將是非常龐大的。 一般我們在測試過程中會將測試用到的數(shù)據(jù)以參數(shù)的形式傳入到測試用例中,并為每條測試數(shù)據(jù)生成一 個測試結(jié)果。這時候可以使用 fixture 的參數(shù)化功能,在 fixture 方法加上裝飾器 @pytest.fixture(params=[1,2,3]) ,就會傳入三個數(shù)據(jù) 1、2、3,分別將這三個數(shù)據(jù)傳入到用例當(dāng) 中。這里傳入的數(shù)據(jù)類型是個列表。傳入的數(shù)據(jù)需要使用一個固定的參數(shù)名 request 來接收。
創(chuàng)建文件名為“test_params.py”,代碼如下:
運行結(jié)果如下:
從運行結(jié)果可以看出,對于 params 里面的每個值,fixture 都會去調(diào)用執(zhí)行一次,使用 request.param 來 接受參數(shù)化的數(shù)據(jù),并且為每一個測試數(shù)據(jù)生成一個測試結(jié)果。在測試工作中使用這種參數(shù)化的方式, 代碼量會大大的減少,并且便于閱讀與維護。
第三方插件介紹
控制用例的執(zhí)行順序
當(dāng)一個目錄下有很多模塊,甚至有很多子目錄。每個目錄下也有大量的測試用例。pytest 加載所有的測 試用例的順序是按照 pytest 的自定義的規(guī)則(不同的模塊間是按照模塊名字的 ASCII 碼順序排列,同 一模塊間是按照定義的前后順序加載的)。如果想指定用例的順序,可以使用 pytest-ordering 插件,指 定用例的執(zhí)行順序只需要在測試用例的方法前面加上裝飾器 @pytest.mark.run(order=[num]) 設(shè)置 order 的對應(yīng)的 num 值,它就可以按照 num 的大小順序來執(zhí)行(由小到大的順序執(zhí)行,負數(shù)反之)。
應(yīng)用場景:
有時運行測試用例需要指定它的順序,比如有些場景需要先要登錄,才能執(zhí)行后續(xù)的流程(比如購物流 程,下單流程),這時就需要指定測試用例的順序。通過 pytest-ordering 這個插件可以完成用例 順序的指定。
安裝
案例
創(chuàng)建一個測試文件“test_order.py”,代碼如下
執(zhí)行結(jié)果,如下查看執(zhí)行順序:
從上面的執(zhí)行結(jié)果可以看出,執(zhí)行時以 order 的順序執(zhí)行:order=1,order=3,order=-1。(1 最先執(zhí) 行,-1 代表倒數(shù)第一個執(zhí)行)
多線程并行與分布式執(zhí)行
應(yīng)用場景:
假如項目中有測試用例 1000 條,一條測試用例需要執(zhí)行 1 分鐘,一個測試人員需要 1000 分鐘才能 完成一輪回歸測試。通常我們會用人力成本換取時間成本,加幾個人一起執(zhí)行,時間就會縮短。如果 10 人一起執(zhí)行只需要 100 分鐘,這就是一種并行測試,分布式的場景。
pytest-xdist 是 pytest 分布式執(zhí)行插件,這款插件允許用戶將測試并發(fā)執(zhí)行(進程級并發(fā)),使用 這款插件執(zhí)行用例是隨機的,為了保證各個測試用例能在各自獨立進程里正確的執(zhí)行,應(yīng)該保證測試用 例的獨立性(這也符合測試用例設(shè)計的最佳實踐)。
安裝
多個 CPU 并行執(zhí)行用例,需要在 pytest 后面添加 -n 參數(shù),如果參數(shù)為 auto,會自動檢測系統(tǒng)的 CPU 數(shù)目。如果參數(shù)為數(shù)字,則指定運行測試的處理器進程數(shù)。
案例
某個項目有 200 條測試用例,每條測試用例之間沒有關(guān)聯(lián)關(guān)系,互不影響。這 200 條測試用例需要在 1 小時之內(nèi)測試完成,可以加個 -n 參數(shù),使用多 CPU 并行測試。
運行方法
進入到項目目錄下,執(zhí)行 pytest 可以將項目目錄下所有測試用例識別出來并且運行,加上 -n 參數(shù),可 以指定 4 個 CPU 并發(fā)執(zhí)行。如果設(shè)置的 CPU 數(shù)大于系統(tǒng) CPU 個數(shù),則會按照當(dāng)前 CPU 的實際個數(shù) 執(zhí)行.
結(jié)合 PYTEST-HTML 生成測試報告
測試報告通常在項目中尤為重要,報告可以體現(xiàn)測試人員的工作量,開發(fā)人員可以從測試報告中了解缺 陷的情況,因此測試報告在測試過程中的地位至關(guān)重要,測試報告為糾正軟件存在的質(zhì)量問題提供依 據(jù),為軟件驗收和交付打下基礎(chǔ)。
測試報告根據(jù)內(nèi)容的側(cè)重點,可以分為 “版本測試報告” 和 “總結(jié)測試報告”。執(zhí)行完 pytest 測試 用例,可以使用 pytest-html 插件生成 HTML 格式的測試報告。
安裝
執(zhí)行方法
結(jié)合pytest-xdist使用
生成測試報告
如下圖:

生成的測試報告最終是 HTML 格式,報告內(nèi)容包括標題、運行時間、環(huán)境、匯總結(jié)果以及用例的通過 個數(shù)、跳過個數(shù)、失敗個數(shù)、錯誤個數(shù),重新運行個數(shù)、以及錯誤的詳細展示信息。 報告會生成在運行腳本的同一路徑下,需要指定路徑添加 --html=path/to/html/report.html 這個 參數(shù)配置報告的路徑。如果不添加 --self-contained-html 這個參數(shù),生成報告的 CSS 文件是獨立 的,分享的時候容易數(shù)據(jù)丟失。
assert 斷言使用
編寫代碼時,我們經(jīng)常會做出一些假設(shè),斷言就是用于在代碼中驗證這些假設(shè)。斷言表示為一些布爾表 達式,測試人員通常會加一些斷言來判斷中間過程的正確性。
斷言支持最常見的表達式,包括調(diào)用,屬性,比較以及二元和一元運算符。 Python 使用 assert(斷 言)用于判斷一個表達式的正確與否,在表達式條件為 False 的時候觸發(fā)異常。
使用方法
案例如下:
如果沒有斷言,沒有辦法判定用例中每一個測試步驟結(jié)果的正確性。在項目中適當(dāng)?shù)氖褂脭嘌詫Υa的 結(jié)構(gòu)、屬性、功能、安全性等場景檢查與驗證。