一篇文章為你揭秘pytest的基本用法


該文章是從我個人的微信公眾號上復制過來的,因此有些圖片不能正常顯示 ,懶得去一個個重新處理圖片了,大家可以點擊微信公眾號的鏈接查看也是一樣的:

 

 

 

一篇文章為你揭秘pytest

 

 

 

pytest是一個測試框架,功能與unittest類似,完全兼容unittest的功能。一般做接口測試的時候,以前用的多的是python+requests+httptestrunner完成接口自動化測試與報告生成,看到現在很多都在用pytest框架,我也來學習一下,接口測試中pytest應用廣泛的是通過python+pytest+allure生成測試報告,報告格式比較美觀。

 

文章比較長,先簡單概述一下本文的大概內容:

1、環境搭建以及pytest是怎么運行的,如何識別有效用例

2、用例執行順序、參數傳遞、數據驅動

3、斷言,以及常見的pytest裝飾器

4、測試報告生成,包括自帶的pytest的報告以及集成allure的報告。

 

pytest安裝

pip install -U pytest

查看安裝版本:

cmd窗口輸入:pytest --version ,會在窗口中輸出類似下面格式的一句話:

This is pytest version 5.4.3, imported from d:\python38\lib\site-packages\pytest\__init__.py

 

用例的識別與運行

用例編寫規范

  • 測試文件以test_開頭(或者以_test結尾)

    pytest會找當前以及遞歸查找子文件夾下面所有的test_*.py或*_test.py的文件,把其當作測試文件(除非顯式指定文件所在路徑)

  • 測試類名稱以Test開頭,並且不能帶有init方法

    如果類名稱以Test開頭的class類中包含了init方法,則會觸發告警,提示PytestCollectionWarning: cannot collect test class 'TestXXX'

  • 測試函數以test_開頭

  • 斷言使用基本的assert即可

 

運行參數

你們可能會有這樣的疑問,現在大家都在用類似pycharm的IDE工具,為什么還要去學習命令行運行的參數和方式呢?

pytest框架是一個測試框架,如果需要集成到jenkins上的話,是需要用命令行的方式去執行的,有時候要執行多個用例的時候,用命令行文件比較方便。

pytest可以在命令行執行,在命令行執行的時候,可以帶很多參數,下面介紹幾種常用到的參數用法:(使用pytest --help可以看到命令參數的幫助文檔)

  • 不帶參數執行

使用方法:pytest 或者 py.test  ,  將會讀取當前路徑下所有符合規則的文件,類,方法,函數全部執行

  • -v 參數

打印詳細運行的日志信息,方便定位問題

  • -s參數

可以在控制台輸出結果,當代碼中有用到print語句輸出信息時,不加這個參數的話,控制台是不會顯示print的內容的

  • -k參數

使用該參數可以指定運行滿足要求的用例。用法如下:

pytest -k "類名"pytest -k "方法名"pytest -k "類名 and not 方法名"

注意: -k參數后面跟的引號只能用雙引號"",不能用單引號'',否則不會識別到用例,運行會報錯

  • -x參數

遇到用例執行失敗或斷言失敗,立即停止運行,不執行后面的用例。

  • --maxfail參數

設置允許失敗的用例數,超過這個閾值時,停止運行。

pytest --maxfail=num ,失敗用例數>=num時,停止運行 

  • -m參數

按照標簽名運行所有包含某個標簽的用例,需要在測試用例上面都加上裝飾符@pytest.mark.標記名。使用-m選項,可以使表達式指定多個標記名。使用-m "mark1 and mark2"可以同時選中帶有這兩個標記的所有測試用例。使用-m "mark1 and  not mark2"則會選中帶mark1標記且不帶mark2標記的測試用例,使用-m "mark1 or mark2"則會選中帶有mark1或者mark2的所有測試用例。

用例標記使用用法如下:

import pytest@pytest.mark.mark1@pytest.mark.mark2def test_a002(self):    print('this is test_a002 method')

使用-m參數運行時,有可能會提示

PytestUnknownMarkWarning: Unknown pytest.mark.xxx - is this a typo?

這只是一個告警,不影響實際執行結果。處理方式有以下幾種:

方法一:在測試用例文件的根目錄新建conftest.py,內容如下:


# 單標簽處理方式def pytest_configure(config): config.addinivalue_line( "markers", "mark1" # test 是標簽名 )
# 多標簽處理方式def pytest_configure(config): marker_list = ["mark1", "mark2"] # 標簽名集合 for markers in marker_list: config.addinivalue_line( "markers", markers )

方法二:在項目根路徑或者用例目錄下新建一個pytest.ini文件,內容如下:

[pytest]markers= mark1 mark2 mark3或者用如下格式:[pytest]markers=    mark1:this is test1 method mark    mark2:this is test2 method mark    mark3:this is test3 method mark 

注意:有多個mark的時候,換行寫,要注意縮進,不縮進是無法識別的,每個mark名稱后面是可以加冒號,然后備注mark的相關詳細描述信息。

方法三:在pytest.ini文件中設置告警過濾,這樣可以避免由於mark標記使用過多時,要一個一個配置,比較麻煩。

具體使用方法可以參考官方文檔:

https://docs.pytest.org/en/latest/warnings.html

[pytest]addopts = -p no:warnings或者:[pytest]filterwarnings = error ignore::UserWarning

 

 

運行模式

pytest提供了多種運行模式,可以指定某個模塊,執行單個pytest模塊進行調試,也可以單獨運行某個類下面的某個測試方法。

命令行運行具體使用方法如下:

pytest 文件名.pypytest 文件名.py::類名pytest 文件名.py::類名::方法名

也可以在pycharm中運行pytest用例

1、先打開Pycharm設置->Tools->Python Integrated Tools->Testing:pytest    

(需要安裝pytest依賴,然后符合編寫規則的測試用例都能被pycharm識別出來,會在用例前面出現一個綠色的執行按鈕,點擊這個按鈕就能執行某個方法或者某個類)

 

pytest 框架結構

與unittest類似,執行用例前后會執行setup、teardown來增加用例的前置和后置條件。

pytest的前置和后置條件大概有這么幾類:

  • 模塊級(setup_module/teardown_module)

在模塊始末調用

  • 函數級(setup_function/teardown_function)

在函數始末調用(在類外部)

  • 類級(setup_class/teardown_class)

在類始末調用(在類中)

  • 方法級(setup_method/teardown_method)

在方法始末調用(在類中)

  • 方法級(setup/teardown)

在方法始末調用(在類中)

調用順序:

setup_module>setup_function>teardown_function>setup_class>setup_method>setup>teardown>teardown_method>teardown_class>teardown_module

注意事項:

1、其中函數級的setup_function/teardown_function是在class類外部調用的,寫在class類中是沒用的,不會調用

2、(setup_method/teardown) 與 (setup/teardown)功能是一樣的,優先級是先執行setup_method,在執行setup。一般二者用其中一個即可.

驗證上面的執行順序,可以執行下面的腳本,

在一個test開頭的py文件里面,編寫一下腳本:def setup_module(): print('\n 這是setup_module方法,只執行一次,當有多個測試類的時候使用')def teardown_module(): print('這是 teardown_module方法,只執行一次,當有多個測試類的時候使用')def teardown_module(): print('這是 teardown_module方法,只執行一次,當有多個測試類的時候使用')def setup_function(): print('這是 setup_function方法,只執行一次,當有多個測試類的時候使用')def teardown_function(): print('這是 teardown_function方法,只執行一次,當有多個測試類的時候使用')def test_five(): print('this is test_five method')def test_six(): print('this is test_six method')class TestPytest01:
def setup_class(self): print('調用了setup_class1方法')
def teardown_class(self): print('調用了teardown_class1方法')
def setup_method(self): print('執行測試方法前的setup1操作')
def teardown_method(self): print('執行測試方法后的teardown1操作')
def test_one(self): print('this is test_one method')
def test_two(self): print('this is test_two method')
def setup(self): print('this is setup 方法') def teardown(self): print('this is teardown 方法')
class TestPytest02: def setup_class(self): print('調用了setup_class2方法')
def teardown_class(self): print('調用了teardown_class2方法')
def setup_method(self): print('執行測試方法前的setup2操作')
def teardown_method(self): print('執行測試方法后的teardown2操作')
def test_three(self): print('this is test_three method')
def test_four(self): print('this is test_four method')

然后看打印的輸出結果:

 

控制用例的執行順序

pytest默認的執行順序是按照文件名以及測試方法名稱排序執行的,如果想指定用例的順序,可以使用pytest-ordering插件,在測試方法前面加上裝飾器@pytest.mark.run(order=num),就可以按照num的大小順序來執行。

安裝:

pip install pytest-ordering

案例:

import pytestclass TestPytest: @pytest.mark.run(order=-2) def test_03(self): print('test_03')
@pytest.mark.run(order=-3) def test_01(self): print('test_01')
@pytest.mark.run(order=4) def test_02(self): print('test_02')

執行結果如下:

注意:按照num排序時,正整數在前,負數在后面,然后統一按照從小到大的順序執行。(我目前使用的是pytest5.4.3版本,不排除以后版本更改排序規則)

 

pytest fixtures

pytest中可以使用@pytest.fixture裝飾器來裝飾一個方法,被裝飾方法的方法名可以作為一個參數傳入到測試方法中。可以通過這種方式來完成測試之前的初始化操作,也可以返回數據給測試函數。

import pytestclass TestFixture: @pytest.fixture() def login(self): return 11
def test_001(self, login): assert 1+10 ==login

 

fixture的scope參數:

根據作用范圍大小范圍划分,分別是:session>module>class>function.

@pytest.fixture(scope='function') scope的默認值是function
  • function函數或者方法級別都會被調用

  • class類級別調用一次

  • module模塊級別調用一次

  • session是多個文件調用一次,可以跨.py文件調用,每個.py文件就是module

通過以下腳本可以測試一下scope的作用范圍:

通過更改scope的枚舉值,即可看到效果,可以看到print('調用login方法')在不同的scope選項下,打印出來的次數是不一樣的。

import pytest
@pytest.fixture(scope='class')def login(): print('調用login方法') return 11
class TestFixture:
def test_001(self, login): print('this is test_001方法') assert 1+10 ==login
def test_002(self, login): print('this is test_001方法') assert 1+10 ==login
class TestFixture1:
def test_003(self, login): print('this is test_003方法') assert 1+10 ==login

conftest.py文件

一般用於scope='session'級別的fixture。conftest.py被pytest視為一個本地插件庫,使用conftest.py的規則:

1、conftest.py這個文件名是固定的,不可以更改

2、conftest.py與運行用例在同一個包下,並且該包中要有__init__.py文件

3、使用的時候不需要導入conftest.py,pytest會自動加載,放到哪個package下,就在這個package內有效。

 

fixture的autouse參數:

如果想讓每條測試用例都添加fixture功能,那么可以使用@pytest.fixture里面的autouse參數,autouse='true'則會自動應用到所有用例中。

用法如下:

使用fixture傳遞測試數據

fixture的param參數可以用來傳遞測試數據,實現數據驅動的效果,避免出現冗余代碼。可以大大減少代碼量,並且便於閱讀和維護。傳入的數據需要使用一個固定的參數名request來接收,代碼如下:

import pytest
@pytest.fixture(params={1,2,3})def data(request): return request.param
def test_data(data): print("測試數據{data}") assert data<10

運行結果:

 

pytest使用pytest-xdist並行運行測試

pytest-xdist是pytest里面的一個分布式執行的插件,可以多個CPU或主機執行。這個是進程級的並發,需要保證測試用例之間的獨立性,插件是動態決定測試用例執行順序,如果互相之間有依賴,可能會導致執行失敗/達不到預期的結果。

安裝:pip install pytest-xdist

用法:

pytest -n auto 或者 pytest -n num 

參數為auto時,系統會自動檢測CPU核數,如果參數為num數字的話,則表示指定運行的處理器進程數量。

 

pytest使用pytest-html生成簡易測試報告

安裝:pip install pytest-html

使用方法:pytest --html=xxxx/report.html   (通過這種方式,生成的html報告,css文件是獨立的,發給其他人的時候要一起帶上css樣式文件)

pytest --html=xxxx/report.html --self-contained-html  (使用self-contained-html 參數,會將css樣式文件的內容直接寫到html文件中)

生成的報告樣式如下:

 

報告中會包含Environment和Summary以及Results的相關數據,如果想要在Environment和Summary下添加一些個性化的內容展示到報告中的話,可以在conftest.py文件中添加以下代碼:

import pytestfrom py._xmlgen import html
# Environment下添加配置項或者修改已有配置項d的值def pytest_configure(config): config._metadata['測試地址'] = '192.168.1.XXX' config._metadata['項目描述'] = '這是XXX項目測試報告' config._metadata['Python'] = '2.7' #報告中默認會有python版本,可以自己手動修改
# Summary下添加個性化的內容展示@pytest.mark.optionalhookdef pytest_html_results_summary(prefix, summary, postfix): prefix.extend([html.p("測試人: 小博")])

加上以上代碼后,運行生成的報告如下:

 

pytest斷言

使用過unittest框架的都知道,unittest里面封裝了很多的斷言方法,有assertEqua、assertNotEqual等好幾十個斷言的方法,在pytest中,斷言直接使用assert關鍵字就行:

assert xx:判斷xx為真

assert not xx:判斷xx不為真

assert a in b:判斷b是否包含a

assert a == b:判斷a等於b

assert a !=b:判斷a不等於b

斷言要做什么判斷,可以自己去定義。也可以在assert后面加上斷言失敗后的描述信息:

assert  a>b,'斷言失敗,實際結果是a<b'


pytest parametrize參數化

先來看一下parametrize()的方法源碼:

def parametrize(self,argnames, argvalues, indirect=False, ids=None, scope=None):
  • 主要參數說明:

argsnames:參數名,是一個字符串,多個參數名中間可以用逗號分隔

argsvalues:參數對應的值,是由參數組成的列表,列表中有幾個元素,就會生成幾條用例,參數名和參數值的數量要相等。

indirect:該參數值默認為False,表示argnames就是普通的參數,如果將該值設置為True,則可以用來將參數傳入到fixture方法中。

ids:用於標志用例的一個id字段,默認可以不傳,會自動用argvalues填充,ids參數可以用來區分測試方法的標識。

scope:聲明argnames中參數的作用域,進而影響到測試用例的收集順序

  • parametrize使用方法:

單個參數:

@pytest.mark.parametrize('a',[1,2,3,4] )def test_ddt01(a): assert a<5

輸出結果:

 

多個參數:

@pytest.mark.parametrize('a,b',[("1+1",2),("1+2",3)])def test_ddt02(a,b): assert eval(a) == b

 

多次使用parametrize的用法:

對同一個方法使用多次@pytest.mark.parametrize裝飾器

@pytest.mark.parametrize('a',[1,2])@pytest.mark.parametrize('b',[1,2])def test_ddt03(a,b): print(f'數據組合 a:{a}, b:{b}')

ids參數用法及效果:

@pytest.mark.parametrize('a',[1,2,3 ],ids=('id-1','id-2','id-3' ))def test_ddt04(a): assert a<5

 

indirect用法:

使用indirectTrue,pytest可以實現將參數傳入到fixture方法中,也可以在當前測試用例中使用。

@pytest.fixture(scope='module')def fun_a(request): print(f'fun_a:{request.param}') return request.param
# indirect=True 聲明fun_a是個函數@pytest.mark.parametrize('fun_a',[9,8,7] ,indirect=True)def test_ddt05(fun_a): print(f'a:{fun_a}') assert fun_a<10

 

scope參數用法及結果演示:

import pytest
@pytest.mark.parametrize('test_input, expected', [(1, 2), (3, 4),(5,6)], scope='module')def test_scope1(test_input, expected): pass
@pytest.mark.parametrize('test_input, expected', [(1, 2), (3, 4),(5,6)], scope='module')def test_scope2(test_input, expected): pass

 

pytest結合YAML實現數據驅動

在實際測試工作中,通常需要對多組不同餓的輸入數據,進行同樣的測試操作步驟,可以將多組測試數據以數據驅動的形式注入,可以做到測試數據和測試用例分別進行管理。常見的外部數據源可以用YAML、Json、Excel、CSV等方式進行管理。

下面以YAML為例,簡單演示一下如何實現數據驅動:

安裝: pip install PyYAML

案例:

創建一個testdata的文件夾,在下面創建data.yml和test_yaml.py文件,內容如下:

data.yaml:- - 1 - 2- - 20 - 30
test_yaml.py:import pytestimport yaml
@pytest.mark.parametrize('a,b',yaml.safe_load(open('data.yml',encoding='utf-8')))def test_add(a,b): print(f'a+b = {a+b}')

輸出結果:

 

pytest結合allure生成測試報告

Allure框架是一種靈活的、輕量級、支持多語言的測試報告工具,報告美觀清晰、一目了然。同時支持多種語言,包括Java、Python、JavaScript、Ruby、Groovy、PHP、.Net、Scala等。

環境搭建:

1、以windows系統為例(先安裝好JDK並配置環境變量),先下載allure的命令行工具進行安裝。下載地址可從github上進行下載:

https://github.com/allure-framework/allure2/releases

github如果下載過慢的話,可以從我的網盤里面下載:

鏈接:https://pan.baidu.com/s/1CJvL_jJuJhFAFP0olUnlCA  

提取碼:1234

下載最新的安裝包后,解壓,配置環境變量。

新建一個ALLURE_HOME的環境變量,value指向解壓后的根路徑,,我電腦上的是:G:\devops\allure-2.9.0

然后在PATH中加入%ALLURE_HOME%\bin 

之所以要單獨配置解壓后的路徑為ALLURE_HOME,是為了以后更換版本后更改環境變量比較方便。

配置好后,在cmd窗口輸入 allure --version 會打印出安裝的版本。

2、安裝python的allure-pytest插件

pip install -U allure-pytest

 

具體使用方法:

步驟一:在會用pytest執行用例的時候,指定參數 --allure選項及結果數據保存的目錄:

pytest --alluredir=./tempdir/data 

pytest --alluredir=./tempdir/data  --clean-alluredir 

加--clean-alluredir選項會先清理數據目錄,再重新生成新的數據,不清理也不會影響報告的生成。

步驟二:

  • 使用allure serve 打開報告:

在cmd窗口輸入allure serve ./tempdir/data ,就會自動打開瀏覽器顯示報告:

 

  • 使用allure ganerate命令生成html格式報告

cmd窗口輸入如下命令:

allure generate ./tempdir/data -o ./report --clean 

命令說明:

 ./tempdir/data 指測試數據目錄, ./report 指html報告生成的位置, --clean指先清空測試報告目錄再重新生成新的測試報告。

需要使用下面的命令打開報告,直接打開html文件,看不到數據:

allure open -h 127.0.01 -p 8088  ./report/

到此,allure報告就生成了,至於報告怎么去分析和查看,可以將報告切換為中文版本自己去進行分析即可。

以上就是pytest常見的一些用法,適合新手入門了解,后續有時間會繼續補充pytest的一些其他語法和用法以及擴展功能,歡迎關注小編,能及時獲取下次更新喔!

 

如果覺得這篇文章對你有幫助,請分享給身邊的朋友一起學習,謝謝!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM