<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
Python測試框架之前一直用的是unittest+HTMLTestRunner,聽到有人說pytest很好用,所以這段時間就看了看pytest檔案,在這裡做個記錄。
官方檔案介紹:
Pytest is a framework that makes building simple and scalable tests easy. Tests are expressive and readable—no boilerplate code required. Get started in minutes with a small unit test or complex functional test for your application or library.
pytest是一個非常成熟的全功能的Python測試框架,主要有以下幾個特點:
pip install -U pytest
pytest --version # 會展示當前已安裝版本
官方檔案:https://docs.pytest.org/en/latest/contents.html
在pytest框架中,有如下約束:
# file_name: test_abc.py import pytest # 引入pytest包 def test_a(): # test開頭的測試函數 print("------->test_a") assert 1 # 斷言成功 def test_b(): print("------->test_b") assert 0 # 斷言失敗 if __name__ == '__main__': pytest.main("-s test_abc.py") # 呼叫pytest的main函數執行測試
1.測試類主函數模式
pytest.main("-s test_abc.py")
2.命令列模式
pytest 檔案路徑/測試檔名 例如:pytest ./test_abc.py
Exit code 0 所有用例執行完畢,全部通過
Exit code 1 所有用例執行完畢,存在Failed的測試用例
Exit code 2 使用者中斷了測試的執行
Exit code 3 測試執行過程發生了內部錯誤
Exit code 4 pytest 命令列使用錯誤
Exit code 5 未採集到可用測試用例檔案
檢視 pytest 版本
pytest --version
顯示可用的內建函數引數
pytest --fixtures
通過命令列檢視幫助資訊及組態檔選項
pytest --help
1.在第N個用例失敗後,結束測試執行
pytest -x # 第01次失敗,就停止測試 pytest --maxfail=2 # 出現2個失敗就終止測試
2.指定測試模組
pytest test_mod.py
3.指定測試目錄
pytest testing/
4.通過關鍵字表示式過濾執行
pytest -k "MyClass and not method"
這條命令會匹配檔名、類名、方法名匹配表示式的用例,這裡這條命令會執行 TestMyClass.test_something, 不會執行 TestMyClass.test_method_simple
5.通過 node id 指定測試用例
nodeid由模組檔名、分隔符、類名、方法名、引數構成,舉例如下:
執行模組中的指定用例
pytest test_mod.py::test_func
執行模組中的指定方法
ytest test_mod.py::TestClass::test_method
6.通過標記表示式執行
pytest -m slow
這條命令會執行被裝飾器 @pytest.mark.slow 裝飾的所有測試用例
7.通過包執行測試
pytest --pyargs pkg.testing
這條命令會自動匯入包 pkg.testing,並使用該包所在的目錄,執行下面的用例。
當cases量很多時,執行時間也會變的很長,如果想縮短指令碼執行的時長,就可以用多程序來執行。
安裝pytest-xdist:
pip install -U pytest-xdist
執行模式:
pytest test_se.py -n NUM
其中NUM填寫並行的程序數。
在做介面測試時,有事會遇到503或短時的網路波動,導致case執行失敗,而這並非是我們期望的結果,此時可以就可以通過重試執行cases的方式來解決。
安裝pytest-rerunfailures:
pip install -U pytest-rerunfailures
執行模式:
pytest test_se.py --reruns NUM
NUM填寫重試的次數。
在執行測試指令碼時,為了偵錯或列印一些內容,我們會在程式碼中加一些print內容,但是在執行pytest時,這些內容不會顯示出來。如果帶上-s,就可以顯示了。
執行模式:
pytest test_se.py -s
另外,pytest的多種執行模式是可以疊加執行的,比如說,你想同時執行4個程序,又想列印出print的內容。可以用:
pytest test_se.py -s -n 4
1.setup和teardown主要分為:模組級,類級,功能級,函數級。
2.存在於測試類內部
程式碼範例:
執行於測試方法的始末,即:執行一次測試函數會執行一次setup和teardown
import pytest class Test_ABC: # 函數級開始 def setup(self): print("------->setup_method") # 函數級結束 def teardown(self): print("------->teardown_method") def test_a(self): print("------->test_a") assert 1 def test_b(self): print("------->test_b") if __name__ == '__main__': pytest.main("-s test_abc.py")
執行結果: test_abc.py ------->setup_method # 第一次 setup() ------->test_a . ------->teardown_method # 第一次 teardown() ------->setup_method # 第二次 setup() ------->test_b . ------->teardown_method # 第二次 teardown()
執行於測試類的始末,即:在一個測試內只執行一次setup_class和teardown_class,不關心測試類內有多少個測試函數。
程式碼範例:
import pytest class Test_ABC: # 測試類級開始 def setup_class(self): print("------->setup_class") # 測試類級結束 def teardown_class(self): print("------->teardown_class") def test_a(self): print("------->test_a") assert 1 def test_b(self): print("------->test_b") if __name__ == '__main__': pytest.main("-s test_abc.py")
執行結果: test_abc.py ------->setup_class # 第一次 setup_class() ------->test_a . ------->test_b F ------->teardown_class # 第一次 teardown_class()
pytest的組態檔通常放在測試目錄下,名稱為pytest.ini,命令列執行時會使用該組態檔中的設定.
#設定pytest命令列執行引數 [pytest] addopts = -s ... # 空格分隔,可新增多個命令列引數 -所有引數均為外掛包的引數設定測試搜尋的路徑 testpaths = ./scripts # 當前目錄下的scripts資料夾 -可自定義 #設定測試搜尋的檔名稱 python_files = test*.py #當前目錄下的scripts資料夾下,以test開頭,以.py結尾的所有檔案 -可自定義 設定測試搜尋的測試類名 python_classes = Test_* #當前目錄下的scripts資料夾下,以test開頭,以.py結尾的所有檔案中,以Test開頭的類 -可自定義 設定測試搜尋的測試函數名 python_functions = test_* #當前目錄下的scripts資料夾下,以test開頭,以.py結尾的所有檔案中,以Test開頭的類內,以test_開頭的方法 -可自定義
外掛列表網址:https://plugincompat.herokuapp.com
包含很多外掛包,大家可依據工作的需求選擇使用。
1.檔案路徑:
- Test_App - - test_abc.py - - pytest.ini
2.pyetst.ini組態檔內容:
[pytest] # 命令列引數 addopts = -s # 搜尋檔名 python_files = test_*.py # 搜尋的類名 python_classes = Test_* #搜尋的函數名 python_functions = test_*
pytest-HTML是一個外掛,pytest用於生成測試結果的HTML報告。相容Python 2.7,3.6
安裝方式:pip install pytest-html
pip install pytest-html
通過命令列方式,生成xml/html格式的測試報告,儲存於使用者指定路徑。外掛名稱:pytest-html
使用方法: 命令列格式:pytest --html=使用者路徑/report.html
範例:
import pytest class Test_ABC: def setup_class(self): print("------->setup_class") def teardown_class(self): print("------->teardown_class") def test_a(self): print("------->test_a") assert 1 def test_b(self): print("------->test_b") assert 0 # 斷言失敗``` 執行方式: 1.修改Test_App/pytest.ini檔案,新增報告引數,即:addopts = -s --html=./report.html # -s:輸出程式執行資訊 # --html=./report.html 在當前目錄下生成report.html檔案 ️ 若要生成xml檔案,可將--html=./report.html 改成 --html=./report.xml 2.命令列進入Test_App目錄 3.執行命令: pytest 執行結果: 1.在當前目錄會生成assets資料夾和report.html檔案
前置條件:
1.檔案路徑:
Test_App - - test_abc.py - - pytest.ini
2.pyetst.ini組態檔內容:
[pytest] 命令列引數 addopts = -s 搜尋檔名 python_files = test*.py 搜尋的類名 python_classes = Test* 搜尋的函數名 python_functions = test_*
fixture修飾器來標記固定的工廠函數,在其他函數,模組,類或整個工程呼叫它時會被啟用並優先執行,通常會被用於完成預置處理和重複操作。
方法:
fixture(scope="function", params=None, autouse=False, ids=None, name=None)
常用引數:
scope:被標記方法的作用域
function(default):作用於每個測試方法,每個test都執行一次
class:作用於整個類,每個class的所有test只執行一次
module:作用於整個模組,每個module的所有test只執行一次
session:作用於整個session(慎用),每個session只執行一次
params:(list型別)提供引數資料,供呼叫標記方法的函數使用
autouse:是否自動執行,預設為False不執行,設定為True自動執行
範例:
class Test_ABC: @pytest.fixture() def before(self): print("------->before") def test_a(self,before): # ️ test_a方法傳入了被fixture標識的函數,已變數的形式 print("------->test_a") assert 1 if __name__ == '__main__': pytest.main("-s test_abc.py") 執行結果: test_abc.py ------->before # 發現before會優先於測試函數執行 ------->test_a .
範例:
import pytest @pytest.fixture() # fixture標記的函數可以應用於測試類外部 def before(): print("------->before") @pytest.mark.usefixtures("before") class Test_ABC: def setup(self): print("------->setup") def test_a(self): print("------->test_a") assert 1 if __name__ == '__main__': pytest.main("-s test_abc.py") 執行結果: test_abc.py ------->before # 發現before會優先於測試類執行 ------->setup ------->test_a .
範例:
import pytest @pytest.fixture(autouse=True) # 設定為預設執行 def before(): print("------->before") class Test_ABC: def setup(self): print("------->setup") def test_a(self): print("------->test_a") assert 1 if __name__ == '__main__': pytest.main("-s test_abc.py") 執行結果: test_abc.py ------->before # 發現before自動優先於測試類執行 ------->setup ------->test_a .
範例:
import pytest @pytest.fixture(scope='function',autouse=True) # 作用域設定為function,自動執行 def before(): print("------->before") class Test_ABC: def setup(self): print("------->setup") def test_a(self): print("------->test_a") assert 1 def test_b(self): print("------->test_b") assert 1 if __name__ == '__main__': pytest.main("-s test_abc.py") 執行結果: test_abc.py ------->before # 執行第一次 ------->setup ------->test_a .------->before # 執行第二次 ------->setup ------->test_b .
範例:
import pytest @pytest.fixture(scope='class',autouse=True) # 作用域設定為class,自動執行 def before(): print("------->before") class Test_ABC: def setup(self): print("------->setup") def test_a(self): print("------->test_a") assert 1 def test_b(self): print("------->test_b") assert 1 if __name__ == '__main__': pytest.main("-s test_abc.py") 執行結果: test_abc.py ------->before # 發現只執行一次 ------->setup ------->test_a . ------->setup ------->test_b .
範例一:
import pytest @pytest.fixture() def need_data(): return 2 # 返回數位2 class Test_ABC: def test_a(self,need_data): print("------->test_a") assert need_data != 3 # 拿到返回值做一次斷言 if __name__ == '__main__': pytest.main("-s test_abc.py") 執行結果: test_abc.py ------->test_a . ``
範例二:
import pytest @pytest.fixture(params=[1, 2, 3]) def need_data(request): # 傳入引數request 系統封裝引數 return request.param # 取列表中單個值,預設的取值方式 class Test_ABC: def test_a(self,need_data): print("------->test_a") assert need_data != 3 # 斷言need_data不等於3 if __name__ == '__main__': pytest.main("-s test_abc.py") 執行結果: # 可以發現結果執行了三次 test_abc.py 1 ------->test_a . 2 ------->test_a . 3 ------->test_a F
前置條件:
1.檔案路徑:
- Test_App - - test_abc.py - - pytest.ini
2.pyetst.ini組態檔內容:
[pytest] 命令列引數 addopts = -s 搜尋檔名 python_files = test_*.py 搜尋的類名 python_classes = Test_* 搜尋的函數名 python_functions = test_*
根據特定的條件,不執行標識的測試函數.
方法:
skipif(condition, reason=None)
引數:
condition
:跳過的條件,必傳引數
reason
:標註原因,必傳引數
使用方法:
@pytest.mark.skipif(condition, reason="xxx")
範例:
import pytest class Test_ABC: def setup_class(self): print("------->setup_class") def teardown_class(self): print("------->teardown_class") def test_a(self): print("------->test_a") assert 1 @pytest.mark.skipif(condition=2>1,reason = "跳過該函數") # 跳過測試函數test_b def test_b(self): print("------->test_b") assert 0 執行結果: test_abc.py ------->setup_class ------->test_a #只執行了函數test_a . ------->teardown_class s # 跳過函數```
標記測試函數為失敗函數
方法:
xfail(condition=None, reason=None, raises=None, run=True, strict=False)
常用引數:
condition
:預期失敗的條件,必傳引數
reason
:失敗的原因,必傳引數
使用方法:
@pytest.mark.xfail(condition, reason="xx")
範例:
import pytest class Test_ABC: def setup_class(self): print("------->setup_class") def teardown_class(self): print("------->teardown_class") def test_a(self): print("------->test_a") assert 1 @pytest.mark.xfail(2 > 1, reason="標註為預期失敗") # 標記為預期失敗函數test_b def test_b(self): print("------->test_b") assert 0 執行結果: test_abc.py ------->setup_class ------->test_a . ------->test_b ------->teardown_class x # 失敗標記
方便測試函數對測試屬於的獲取。
方法:
parametrize(argnames, argvalues, indirect=False, ids=None, scope=None)
常用引數:
argnames
:引數名
argvalues
:引數對應值,型別必須為list
當引數為一個時格式:[value]
當引數個數大於一個時,格式為:
[(param_value1,param_value2.....),(param_value1,param_value2.....)]
使用方法:
@pytest.mark.parametrize(argnames,argvalues)
引數值為N個,測試方法就會執行N次
單個引數範例:
import pytest class Test_ABC: def setup_class(self): print("------->setup_class") def teardown_class(self): print("------->teardown_class")
@pytest.mark.parametrize("a",[3,6]) # a引數被賦予兩個值,函數會執行兩遍 def test_a(self,a): # 引數必須和parametrize裡面的引數一致 print("test data:a=%d"%a) assert a%3 == 0 執行結果: test_abc.py ------->setup_class test data:a=3 # 執行第一次取值a=3 . test data:a=6 # 執行第二次取值a=6 . ------->teardown_class
多個引數範例:
import pytest class Test_ABC: def setup_class(self): print("------->setup_class") def teardown_class(self): print("------->teardown_class")
@pytest.mark.parametrize("a,b",[(1,2),(0,3)]) # 引數a,b均被賦予兩個值,函數會執行兩遍 def test_a(self,a,b): # 引數必須和parametrize裡面的引數一致 print("test data:a=%d,b=%d"%(a,b)) assert a+b == 3 執行結果: test_abc.py ------->setup_class test data:a=1,b=2 # 執行第一次取值 a=1,b=2 . test data:a=0,b=3 # 執行第二次取值 a=0,b=3 . ------->teardown_class
函數返回值型別範例:
import pytest def return_test_data(): return [(1,2),(0,3)] class Test_ABC: def setup_class(self): print("------->setup_class") def teardown_class(self): print("------->teardown_class")
@pytest.mark.parametrize("a,b",return_test_data()) # 使用函數返回值的形式傳入引數值 def test_a(self,a,b): print("test data:a=%d,b=%d"%(a,b)) assert a+b == 3 執行結果: test_abc.py ------->setup_class test data:a=1,b=2 # 執行第一次取值 a=1,b=2 . test data:a=0,b=3 # 執行第二次取值 a=0,b=3 . ------->teardown_class
pytest --showlocals # show local variables in tracebacks pytest -l # show local variables (shortcut) pytest --tb=auto # (default) 'long' tracebacks for the first and last # entry, but 'short' style for the other entries pytest --tb=long # exhaustive, informative traceback formatting pytest --tb=short # shorter traceback format pytest --tb=line # only one line per failure pytest --tb=native # Python standard library formatting pytest --tb=no # no traceback at all
--full-trace引數會列印更多的錯誤輸出資訊,比引數 --tb=long 還多,即使是 Ctrl+C 觸發的錯誤,也會列印出來
執行用例的時候,跟引數 --pdb,這樣失敗的時候,每次遇到失敗,會自動跳轉到 PDB
pytest --pdb # 每次遇到失敗都跳轉到 PDB pytest -x --pdb # 第一次遇到失敗就跳轉到 PDB,結束測試執行 pytest --pdb --maxfail=3 # 只有前三次失敗跳轉到 PDB
在用例指令碼中加入如下python程式碼,pytest會自動關閉執行輸出的抓取,這裡,其他test指令碼不會受到影響,帶斷點的test上一個test正常輸出
import pdb; pdb.set_trace()
獲取最慢的10個用例的執行耗時
pytest --durations=10
這種格式的結果檔案可以被Jenkins或其他CI工具解析
pytest --junitxml=path
例如,關閉 doctest 外掛
pytest -p no:doctest
pytest.main() # 基本用法 pytest.main(['-x', 'mytestdir']) # 傳入設定引數 // 指定自定義的或額外的外掛 # content of myinvoke.py import pytest class MyPlugin(object): def pytest_sessionfinish(self): print("*** test run reporting finishing") pytest.main(["-qq"], plugins=[MyPlugin()])
例如你從Gitlab倉庫裡clone了專案組的刀刀同學編寫的測試指令碼到你自己的電腦裡,你想修改些東西,並偵錯,咋辦?可以通過下面的操作快速建立 VirtualEnv
cd <repository> pip install -e .
This will set up a symlink to your code in site-packages, allowing you to edit your code while
your tests run against it as if it were installed.
Setting up your project in development mode lets you avoid having to reinstall every time you want to run your tests,
and is less brittle than mucking about with sys.path to point your tests at local code.
Also consider using tox
pytest可以輸出覆蓋率的html報告
使用命令如下:
pytest -vv --cov=./ --cov-report=html open htmlcov/index.html
有可能遇到報錯:
(venv) zhangxiaofans-MacBook-Pro:mgap-mendel joe$ pytest --cov-report=html usage: pytest [options] [file_or_dir] [file_or_dir] [...] pytest: error: unrecognized arguments: --cov-report=html inifile: None rootdir: /Users/joe/workspace/platform/mgap-mendel/mgap-mendel
原因:
缺少pytest cov的包
解決方法
pip install pytest-cov
以上就是Python測試框架pytest高階用法全面詳解的詳細內容,更多關於Python測試框架pytest的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45