Pytest 入門學習
pytest是一個非常成熟的全功能的Python測試框架,主要特點有以下幾點:
簡單靈活,容易上手;
支持參數化;
能夠支持簡單的單元測試和復雜的功能測試,還可以用來做selenium/appnium等自動化測試、接口自動化測試(pytest+requests);
pytest具有很多第三方插件,并且可以自定義擴展,比較好用的如pytest-selenium(集成selenium)、pytest-html(完美html測試報告生成)、pytest-rerunfailures(失敗case重復執行)、pytest-xdist(多CPU分發)等;
測試用例的skip和xfail處理;
可以很好的和jenkins集成;
一、安裝
安裝
pip install -U pytest
檢查是否安裝成功
pytest --version
This is pytest version 4.5.0, imported from c:\python27\lib\site-packages\pytest.pyc
查看幫助命令
pytest -h
二、快速入門
創建一個test_sample.py
def func(x):
return x + 1
class TestCase():
def test_answer(self):
assert func(3) == 5
運行用例
命令行通過以下命令運行:
運行所有文件:pytest
運行單個文件:pytest test_sample.py
運行結果:
結論:
從上面看出,當用例運行失敗時,會在控制臺打印具體的錯誤信息,包含用例信息及具體錯誤代碼和預期結果。錯誤信息一目了然。
非命令行運行
代碼右鍵運行或直接從pytest.main()運行,返回結果如下:
三、pytest用例識別
pytest會找當前以及遞查找子文件夾下面所有的test_.py或_test.py的文件,把其當作測試文件
在這些文件里,pytest會收集下面的一些函數或方法,當作測試用例:
1、不在類定義中的以test_開頭的函數或方法
2、在以Test開頭的類中(不能包含init方法),以test_開頭的方法
3、pytest也支持unittest模式的用例定義
四、運行用例
1、運行單個用例
使用命令,pytest+文件名 運行,如運行test_class.py
pytest test_class.py
2、運行多個用例
運行多個用例,使用命令pytest
3、運行指定用例
3.1通過匹配關鍵字,運行用例
使用命令,pytest -k keyword 運行指定關鍵字用例
3.2通過用例標記,運行用例
1)用例標記:pytest允許為測試用例添加屬性通過 pytest markers,@pytest.mark,定義方法: @pytest.mark.<name>
2)運行標記的用例,如運行被標記falled的用例:pytest -m falled
結論:
由上圖可看出,文件中被標記為falled的用例被執行。
3、運行文件夾下的用例
使用命令,pytest + 文件夾,可運行該文件夾下的用例,如運行testing文件夾下的用例
結論:
通過 pytest+文件名/ 命令,可運行該文件夾下的所有用例。
4、運行模塊下類內指定的用例
使用命令,pytest+文件名+類名+方法名,指定運行測試用例,格式為:pytest::test_.py::Test::test
結論:
由上圖可以看到,使用命令 pytest::test_sample.py::TestCase::test01,可以運行test_sample.py文件中TestCase類下的test01方法。
五、運行用例,顯示指定結果信息
運行測試用例,顯示總的結果信息,使用命令 pytest -ra
運行測試用例,顯示通過的結果信息,使用命令 pytest -rp
運行測試用例,顯示錯誤結果信息警告信息,使用命令 pytest -rE
運行測試用例,顯示跳過結果信息,使用命令 pytest -rs
======================== short test summary info ========================
SKIPPED [1] test_skip_case.py:4: unconditional skip
SKIPPED [1] test_skip_case.py:9: unconditional skip
六、環境準備和環境清理
pytest使用Fixture功能為測試用例進行環境準備和環境清理,相當于unittest中的setup\teardown,
setupClass\teardownClass。同時對于傳統的setup/teardown函數做了顯著的改進:
1)測試fixture有明確的名稱,通過在函數/模塊/類或者整個項目中激活來使用。
2)測試fixture是模塊化的實現,使用fixture名即可觸發特定的fixture,fixture可以在其他fixture中進行使用
3)測試fixture不僅可以進行簡單的單元測試,也可以進行復雜的功能測試。可以根據配置和組件的選項進行參數化定制測試,或者跨函數/類/模塊或者整個測試過程進行測試。
1、環境準備
使用@pytest.fixture裝飾器來設置一個函數為測試fixture,后面的測試函數調用到fixture名稱時,pytest會檢測到該fixture并加載其中的數據作為參數傳入。定義fixture的方式:在單個測試文件中定義
、多個文件共享fixture、通過設置fixture中的scope指定作用范圍定義,格式為@pytest.fixture(scope=session/module/class/function),其中作用范圍大小為:session>module>class>function。具體實現詳見例子~
1.1單個函數定義fixture
1)創建一個文件test_fixture01.py
@pytest.fixture() # 定義some_data函數為測試fixture
def some_data():
return 42
def test_some_data(some_data): # 測試函數調用some_data,并做斷言
assert some_data == 42
2)調用并執行以上文件:執行命令 pytest --setup-show test_fixture01.py
E:\自動化\pytest框架學習\learn_fixture>pytest --setup-show test_fixture01.py
========================test session starts ============================
platform win32 -- Python 3.7.2, pytest-5.2.2, py-1.8.0, pluggy-0.13.0
rootdir: E:\樂乎自動化\pytest框架學習\learn_fixture
plugins: forked-1.1.1, html-2.0.0, metadata-1.8.0, xdist-1.30.0
collected 1 item
test_fixture01.py
SETUP F some_data
test_fixture01.py::test_some_data (fixtures used: some_data).
TEARDOWN F some_data
========================== 1 passed in 0.12s ==========================
結論:
由上執行結果可以看到,在執行test_some_data用例時,test_some_data調用了測試fixture some_data,并在用例執行前后進行了setup和teardown操作。
1.2多個文件共享fixture
在測試用例實現過程中,當需要使用來自多個文件的fixture時,可以將這些fixture函數寫到conftest.py文件中。使用時,不需要導入fixture函數,pytest會自動檢索。
fixture函數的使用從測試類開始,到測試模塊,然后是conftest.py文件,然后是內置的插件和第三方插件。也可以使用conftest為本地目錄實現插件。
1)修改test_fixture01.py文件,分別改為兩個文件,將測試fixture函數存入到conftest.py文件中,測試函數另起一個文件為test_fixture02.py
content of conftest.py
@pytest.fixture() # 定義some_data函數為測試fixture
def some_data():
return 42
content of test_fixture02.py
def test_some_data(some_data): # 測試函數調用some_data,并做斷言
assert some_data == 42
2)執行多個文件:執行命令 pytest --setup-show test_fixture01.py test_fixture02.py
結論:
由上圖執行結果可看到,當將測試fixture函數放在conftest.py文件中,測試用例調用時,可實現多個文件共享fixture函數。
1.3通過設置fixture中的scope指定作用范圍
1)指定@pytest.fixture(scope="function"),執行文件時,所有測試文件的每個function函數執行時都會調用fixture函數一次。【不指定情況下,默認為funtion】
結論:
當設置scope="funtion"時,每個用例執行前后都會調用一次function。
2)指定@pytest.fixture(scope="class"),執行文件時,每個類執行前后只調用測試fixture一次。
結論:
當設置sope="class"時,在調用類時,只調用一次funtion。
3)指定@pytest.fixture(scope="module"),執行文件時,只調用fixture一次
創建一個test_fixture04.py包含兩個類及一個測試函數,并執行文件:
結論:
從上圖可以看到,在執行測試文件時,執行前和執行后只進行了一次funtion的調用。
4)指定@pytest.fixture(scope="session"),執行一個會話時,只調用fixture一次。
注:一個會話是一次文件的調用,可以同時調用多個文件。
結論:
當設置scope="session"時,只是在整個會話開始前和結束后調用一次function。
2、環境清理
pytest支持在fixture退出作用域的時候執行相關的清理/結束代碼。使用yield而不是return關鍵字的時候,yield后面的語句將會在fixture退出作用域的時候被調用來清理測試用例。
1)創建一個文件test_fixture06.py,包含test fixture和test function兩部分
import pytest
@pytest.fixture(scope=**"module"**)
def something():
print(**"**\n**哈哈哈哈****"**) # setup部分數據
yield # 使用yield后面的語句將會在fixture退出作用域的時候被調用來清理測試用例
print(**"****結束了?****"**)
def test_smtp(something):
print(**"****測試中。。。。****"**)
2)運行文件:pytest -s test_fixture06.py
七、設置斷言
斷言,每個測試用例都需要斷言。unittest中使用unittest自帶的斷言機制,與unittest不同的時,pytest使用的是python自帶的assert關鍵字來進行斷言。
assert關鍵字后面可以接一個表達式,只要表達式的最終結果為True,那么斷言通過,用例執行成功,否則用例執行失敗。斷言失敗有詳細的用例失敗描述。
1、斷言
代碼:
def f():
return 3
def test_function():
assert f() == 4
執行結果:
總結:
從執行結果可以看到,用例斷言失敗了,且有詳細的失敗信息描述,可以一眼看出是哪兒出了問題。
2、斷言異常拋出
八、用例參數化
參數化測試是用于一些測試流程一樣,測試數據不同的測試用例,以此來簡化代碼。
pytest支持使用fixture中通過param="參數集"初始化需要傳入的參數,再將fixture作為參數傳入用例中實現參數化。也可通過使用parametrize支持多個參數化傳入。
1、參數化fixture(參數化1個)
校驗用戶弱密碼~
users文件:
[
{"name":"jack","password":"Iloverose"},
{"name":"rose","password":"Ilovejack"},
{"name":"tom","password":"password123"},
{"name":"mike","password":"password"},
{"name":"james","password":"AGoodPasswordWordShouldBeLongEnough"}
]
用例文件:
'''用例需求:
校驗多個用戶、密碼是否存在弱密碼。
用例設計:
使用參數化形式,一個測試方法傳入user集參數,使用例一次性校驗所有用戶
是否存在弱密碼。
'''
import pytest
import json
users = json.loads(open(**'./user.json'**, **'r'**).read()) # 從user.json文件中讀取出用戶數據
class TestUserPasswordWithParam():
@pytest.fixture(params=users) # 將user作為參數傳入,并返回user中的每個用戶信息。再將此fixture作為參數傳入到用例中數據
def user(self, request):
user_info = request.param # 使用request.param從users中一個一個地拿出數據并返回
return user_info
def test_user_password(self, user):
password = user[**'password'**]
assert len(password) >= 6
msg = **"****用戶****%s****存在弱密碼****"** % (user[**'name'**])
assert password != **'password'**, msg
assert password != **'password123'**, msg
測試結果:
總結:
從上面運行結果可以看到,用例一共運行了5次。
2、parametrize多參數(參數化多個)
此功能,類似unittest中的ddt數據驅動模式
@pytest.mark.parametrize 裝飾器可以讓我們每次參數化fixture的時候傳入多個項目
校驗算數加法:
import pytest
@pytest.mark.parametrize(
**"a,b,c"**, # 參數名---多個參數
[(1, 2, 3), # 參數值---參數值與參數對應,可傳入多個需要校驗的參數值
(3, 4, 7),
(5, 6, 11)]
)
def test_add(a, b, c):
assert a+b == c
測試結果:
總結:
加法校驗case中,傳入了3組參數值,實際用例也運行了3次,每次取不同的數據。
九、跳過用例
當遇到不想運行的用例,可對該用例標記為跳過,在執行測試時,會自動跳轉被標記的用例。使用
@pytest.mark.skip 標記跳過用例,使用@pytest.mark.xfail 標記用例時,則用例失敗執行失敗后,無任何錯誤信息。
下面的詳細的用例代碼:
test_skip_case.py
import pytest
@pytest.mark.skip # skip標記跳過用例,不執行
def test_add_1():
assert 100 + 200 == 400, **"failed"**
@pytest.mark.skip
def test_add_2():
assert 100 + 200 == 300, **"failed"**
@pytest.mark.xfail # xfail標記執行用例,但是不統計執行結果
def test_add_3():
assert 15 + 13 == 28, **"passed"**
@pytest.mark.xfail
def test_add_4():
assert 15 + 13 == 100, **"failed"**
def test_add_5():
assert 3 + 2 == 5, **"passed"**
def test_add_6():
assert 3 + 2 == 6, **"failed"**
執行用例:pytest -v test_skip_case.py
[圖片上傳失敗...(image-f7e8d5-1573551303032)]
可以看到,測試用例文件中,前兩個用例未執行,第三、四個執行了,且第三個執行失敗了,未收集失敗信息。第五、第六個正常執行,第六個執行失敗,顯示具體的失敗追蹤信息。
十、生成測試報告
1、生成HTML格式的測試報告
生成html格式的測試報告,需要用例到插件pytest-html。具體步驟如下:
1)安裝插件:pip install pytest-html
2)執行測試并生成測試報告:pytest -v -s --html=report.html
2、生成XML格式的測試報告
生成junit格式的xml報告,在命令行中加入--junit-xml=path 參數就可以了.
pytest -v --junit-xml=report.xml
十一、常見命令行參數
參考:
https://blog.csdn.net/lb245557472/article/details/90341297)
http://www.testclass.net/pytest
https://blog.csdn.net/crazyskady
http://pytest.org/en/latest/contents.html
https://www.bilibili.com/video/av59183665/