簡介
pytest是python的一種單元測試框架,與python自帶的unittest測試框架相似,可是比unittest框架使用起來更簡潔,效率更高。而且pytest兼容unittest的用例,支持的插件也更多html
安裝java
pip install pytest
簡單上手,建立個test_sample.py文件node
def func(x): return x + 1 def test_answer(): assert func(3) == 5
運行測試,直接在當前文件夾運行pytestpython
collected 1 item test_sample.py F [100%] ================================= FAILURES ================================= _______________________________ test_answer ________________________________ def test_answer(): > assert func(3) == 5 E assert 4 == 5 E + where 4 = func(3) test_sample.py:6: AssertionError ============================ 1 failed in 0.12s =============================
pytest運行規則:查找當前目錄及其子目錄下以test_*.py或*_test.py文件,找到文件後,在文件中找到以test開頭函數並執行。git
以類來封裝用例github
# content of test_class.py class TestClass: def test_one(self): x = "this" assert "h" in x def test_two(self): x = "hello" assert hasattr(x, "check")
運行能夠使用pytest [file_path]指定文件,-q是靜默模式,不會打印用例輸出windows
$ pytest -q test_class.py .F [100%] ================================= FAILURES ================================= ____________________________ TestClass.test_two ____________________________ self = <test_class.TestClass object at 0xdeadbeef> def test_two(self): x = "hello" > assert hasattr(x, "check") E AssertionError: assert False E + where False = hasattr('hello', 'check') test_class.py:8: AssertionError 1 failed, 1 passed in 0.12s
用例設計原則session
- 文件名以test_*.py文件和*_test.py
- 以test_開頭的函數
- 以Test開頭的類
- 以test_開頭的方法
- 全部的包pakege必需要有__init__.py文件
執行用例
1.執行某個目錄下全部的用例oracle
pytest 文件名/
2.執行某一個py文件下用例框架
pytest 腳本名稱.py
3.-k 按關鍵字匹配
pytest -k "MyClass and not method"
這將運行包含與給定字符串表達式匹配的名稱的測試,其中包括Python使用文件名,類名和函數名做爲變量的運算符。 上面的例子將運行TestMyClass.test_something但不運行TestMyClass.test_method_simple
4.按節點運行
每一個收集的測試都分配了一個惟一的nodeid,它由模塊文件名和後跟說明符組成來自參數化的類名,函數名和參數,由:: characters分隔。
運行.py模塊裏面的某個函數
pytest test_mod.py::test_func
運行.py模塊裏面,測試類裏面的某個方法
pytest test_mod.py::TestClass::test_method
5.標記表達式
pytest -m slow
將運行用@ pytest.mark.slow裝飾器修飾的全部測試,slow是本身命名的標記,能夠自定義
import pytest @pytest.mark.finished def test_send_http(): pass def test_something_quick(): pass
運行測試時使用-m選項能夠加上邏輯
>pytest -m "finished and commit" //匹配finished和commit運行 >pytest -m "finished and not merged" //finished運行,merged不運行
6.從包裏面運行
pytest --pyargs pkg.testing
這將導入pkg.testing並使用其文件系統位置來查找和運行測試。
7.在第一個(或N個)失敗後中止
pytest -x # stop after first failure pytest --maxfail=2 # stop after two failures
8.跳過測試
使用pytest.mark.skip標記須要跳過的用例
@pytest.mark.skip(reason="not finished") def test_send_http(): pass
也支持使用 pytest.mark.skipif 爲測試函數指定被忽略的條件
@pytest.mark.skipif(finishflag==Fasle,reason="not finished") def test_send_http(): pass
9.腳本調用執行
直接使用 pytest.main() 像命令行同樣傳遞參數 pytest.main(["-x", "mytestdir"])
用例編寫
斷言
pytest直接使用python assert語法來寫
def f(): return 3 def test_function(): assert f() == 4
斷言中添加消息
assert a % 2 == 0, "value was odd, should be even"
預設與清理
與unittest中的setup和teardown相似,pytest也有這樣的環境清理方法,主要有
-
模塊級(setup_module/teardown_module)開始於模塊始末,全局的
-
函數級(setup_function/teardown_function)只對函數用例生效(不在類中)
-
類級(setup_class/teardown_class)只在類中先後運行一次(在類中)
-
方法級(setup_method/teardown_method)開始於方法始末(在類中)
-
類裏面的(setup/teardown)運行在調用方法的先後
import pytest class TestClass: def setup_class(self): print("setup_class:類中全部用例執行以前") def teardown_class(self): print("teardown_class:類中全部用例執行以前") def setup_method(self): print("setup_method: 每一個用例開始前執行") def teardown_method(self): print("teardown_method: 每一個用例結束後執行") def setup(self): print("setup: 每一個用例開始前執行") def teardown(self): print("teardown: 每一個用例結束後執行") def test_one(self): print("執行第一個用例") def test_two(self): print("執行第二個用例") def setup_module(): print("setup_module:整個.py模塊只執行一次") def teardown_module(): print("teardown_module:整個.py模塊只執行一次") def setup_function(): print("setup_function:每一個方法用例開始前都會執行") def teardown_function(): print("teardown_function:每一個方法用例結束前都會執行") def test_three(): print("執行第三個用例")
使用pytest -s test_sample.py運行,-s參數是爲了顯示用例的打印信息,下面是輸出,能夠看出幾個方法之間的優先級
test_sample.py setup_module:整個.py模塊只執行一次 setup_class:類中全部用例執行以前 setup_method: 每一個用例開始前執行 setup: 每一個用例開始前執行 執行第一個用例 .teardown: 每一個用例結束後執行 teardown_method: 每一個用例結束後執行 setup_method: 每一個用例開始前執行 setup: 每一個用例開始前執行 執行第二個用例 .teardown: 每一個用例結束後執行 teardown_method: 每一個用例結束後執行 teardown_class:類中全部用例執行以前 setup_function:每一個方法用例開始前都會執行 執行第三個用例 .teardown_function:每一個方法用例結束前都會執行 teardown_module:整個.py模塊只執行一次
注意:setup_method和teardown_method的功能和setup/teardown功能是同樣的,通常兩者用其中一個便可;函數裏面用到的setup_function/teardown_function與類裏面的setup_class/teardown_class互不干涉
參數化
使用pytest.mark.parametrize(argnames, argvalues)能夠實現函數的參數化
@pytest.mark.parametrize('text',['test1','test2','test3']) def test_one(text): print(text)
argnames就是形參名稱,argvalues就是待測的一組數據
固件fixture
基本使用
固件Fixture是一些函數,pytest 會在執行測試函數以前(或以後)加載運行它們。主要是爲一些單獨測試用例須要預先設置與清理的狀況下使用的。
不一樣於上面的setup和teardown的就是,能夠自定義函數,能夠指定用例運行,使用方法以下
@pytest.fixture() def text(): print("開始執行") #使用pytest.fixture()裝飾一個函數成爲fixture def test_one(): print("執行第一個用例") def test_two(text): #用例傳入fixture函數名,以此來確認執行 print("執行第二個用例")
使用yield能夠實現固件的拆分運行,yield前在用例前執行,yield後再用例後執行
@pytest.fixture() def text(): print("開始執行") yield #yield 關鍵詞將固件分爲兩部分,yield 以前的代碼屬於預處理,會在測試前執行;yield 以後的代碼屬於後處理,將在測試完成後執行 print("執行完畢") def test_one(): print("執行第一個用例") def test_two(text): print("執行第二個用例")
統一管理
固件能夠直接定義在各測試腳本中,就像上面的例子。更多時候,咱們但願一個固件能夠在更大程度上覆用,這就須要對固件進行集中管理。Pytest 使用文件 conftest.py 集中管理固件。
不用顯式調用 conftest.py,pytest 會自動調用,能夠把 conftest 當作插件來理解
./conftest.py @pytest.fixture() def text(): print("開始執行") yield print("執行完畢") ./test_sample.py def test_one(): print("執行第一個用例") def test_two(text): print("執行第二個用例")
做用域
fixture能夠經過 scope 參數聲明做用域,好比
- function: 函數級,每一個測試函數都會執行一次固件;
- class: 類級別,每一個測試類執行一次,全部方法均可以使用;
- module: 模塊級,每一個模塊執行一次,模塊內函數和方法均可使用;
- session: 會話級,一次測試只執行一次,全部被找到的函數和方法均可用。
./conftest.py @pytest.fixture(scope="module") def text(): print("開始執行") yield print("執行完畢") ./test_sample.py def test_one(text): print("執行第一個用例") def test_two(text): print("執行第二個用例")
執行狀況
test_sample.py 開始執行 執行第一個用例 .執行第二個用例 .執行完畢
若是對於類使用做用域,須要使用 pytest.mark.usefixtures(對函數和方法也適用)
./conftest.py @pytest.fixture(scope="class") def text(): print("開始執行") yield print("執行完畢") ./test_sample.py @pytest.mark.usefixtures('text') class TestClass: def test_one(self): print("執行第一個用例") def test_two(self): print("執行第二個用例")
自動運行
將fixture的autouse參數設置爲True時,能夠不用傳入函數,自動運行
./conftest.py @pytest.fixture(scope="module",autouse=True) def text(): print("開始執行") yield print("執行完畢") ./test_sample.py def test_one(): print("執行第一個用例") def test_two(): print("執行第二個用例")
參數化
使用fixture的params參數能夠實現參數化
./conftest.py @pytest.fixture(scope="module",params=['test1','test2']) def text(request): print("開始執行") yield request.param print("執行完畢") ./test_sample.py def test_one(text): print("執行第一個用例") print(text) def test_two(text): print("執行第二個用例")
固件參數化須要使用 pytest 內置的固件 request,並經過 request.param 獲取參數。
結果以下
test_sample.py 開始執行 執行第一個用例 test1 .執行第二個用例 .執行完畢 開始執行 執行第一個用例 test2 .執行第二個用例 .執行完畢
生成報告
HTML報告
安裝pytest-html
pip install pytest-html
使用方法是,直接在命令行pytest命令後面加--html=<文件名字或者路徑>.html參數就能夠了
pytest --html=report.html
結果以下
上面生成的報告包括html和一個assets文件(裏面是報告CSS樣式),若是要合成一個文件能夠添加下面的參數
pytest --html=report.html --self-contained-html
XML報告
使用命令能夠生成XML格式報告
pytest --junitxml=report.xml
allure報告
1.首先安裝java環境
下載JDK http://www.oracle.com/technetwork/java/javase/downloads/index.html
安裝對應系統的包,如windowsx64是xxx-windows-x64.exe
一路下一步安裝就能夠了
而後在環境變量中添加下面變量
變量名:JAVA_HOME 變量值:C:\Program Files (x86)\Java\jdk1.8.0_91 // 要根據本身的實際路徑配置 變量名:CLASSPATH 變量值:.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar; //記得前面有個"." 變量名:Path 變量值:%JAVA_HOME%\bin;%JAVA_HOME%\jre\bin;
而後再cmd中運行 java -version、java、javac 幾個命令沒有報錯便可
2.安裝allure
下載allure 會跳轉到github,找到link下載
解壓包後進入bin文件,複製路徑並添加到環境變量Path中
cmd運行allure命令,沒有報錯即正確
3.pytest使用
安裝插件
pip install allure-pytest 若是timeout就加 --index-url https://pypi.douban.com/simple 用豆瓣源
進入測試py文件目錄,運行
pytest --alluredir ./report
運行完成後生成report文件,-alluredir後面跟的是文件路徑,能夠自定義
使用allure查看報告,直接啓動allure server後面加報告路徑就行
allure serve report(報告文件夾名)
等一會就生成報告
參考: