Pytest 自動(dòng)化測試框架的使用
Pytest和Unittest測試框架的區(qū)別?
如何區(qū)分這兩者,很簡單unittest作為官方的測試框架,在測試方面更加基礎(chǔ),并且可以再次基礎(chǔ)上進(jìn)行二次開發(fā),同時(shí)在用法上格式會(huì)更加復(fù)雜;而pytest框架作為第三方框架,方便的地方就在于使用更加靈活,并且能夠?qū)υ衭nittest風(fēng)格的測試用例有很好的兼容性,同時(shí)在擴(kuò)展上更加豐富,可通過擴(kuò)展的插件增加使用的場景,比如一些并發(fā)測試等;
Pytest 安裝
pip安裝:
pip install pytest
測試安裝成功:
pytest --help py.test --help
檢查安裝版本:
pytest --version
Pytest 示例
Pytest編寫規(guī)則:
- 測試文件以test_開頭(以_test為結(jié)尾)
- 測試的類以Test開頭;
- 測試的方法以test_開頭
- 斷言使用基本的assert
test_example.py
def count_num(a: list) -> int: ? ? return len(a) ? ? def test_count(): ? ? assert count_num([1, 2, 3]) != 3
執(zhí)行測試:
pytest test_example.py
執(zhí)行結(jié)果:
C:\Users\libuliduobuqiuqiu\Desktop\GitProjects\PythonDemo\pytest>pytest test_example.py -v
================================================================= test session starts =================================================================
platform win32 -- Python 3.6.8, pytest-6.2.5, py-1.10.0, pluggy-1.0.0 -- d:\coding\python3.6\python.exe
cachedir: .pytest_cache
rootdir: C:\Users\libuliduobuqiuqiu\Desktop\GitProjects\PythonDemo\pytest
plugins: Faker-8.11.0
collected 1 item
test_example.py::test_count FAILED [100%]
====================================================================== FAILURES =======================================================================
_____________________________________________________________________ test_count ______________________________________________________________________
def test_count():
> assert count_num([1, 2, 3]) != 3
E assert 3 != 3
E + where 3 = count_num([1, 2, 3])
test_example.py:11: AssertionError
=============================================================== short test summary info ===============================================================
FAILED test_example.py::test_count - assert 3 != 3
================================================================== 1 failed in 0.16s ==================================================================
備注:
- .代表測試通過,F(xiàn)代表測試失??;
- -v顯示詳細(xì)的測試信息, -h顯示pytest命令詳細(xì)的幫助信息;
標(biāo)記
默認(rèn)情況下,pytest會(huì)在當(dāng)前目錄下尋找以test_為開頭(以_test結(jié)尾)的測試文件,并且執(zhí)行文件內(nèi)所有以test_為開頭(以_test為結(jié)尾)的所有函數(shù)和方法;
指定運(yùn)行測試用例,可以通過::顯示標(biāo)記(文件名::類名::方法名)(文件名::函數(shù)名)
pytest test_example3.py::test_odd
指定一些測試用例測試運(yùn)行,可以使用-k模糊匹配
pytest -k example
通過pytest.mark.skip()或者pytest.makr.skipif()條件表達(dá)式,跳過指定的測試用例
import pytest
test_flag = False
@pytest.mark.skip()
def test_odd():
num = random.randint(0, 100)
assert num % 2 == 1
@pytest.mark.skipif(test_flag is False, reason="test_flag is False")
def test_even():
num = random.randint(0, 1000)
assert num % 2 == 0
通過pytest.raises()捕獲測試用例可能拋出的異常
def test_zero():
num = 0
with pytest.raises(ZeroDivisionError) as e:
num = 1/0
exc_msg = e.value.args[0]
print(exc_msg)
assert num == 0
預(yù)先知道測試用例會(huì)失敗,但是不想跳過,需要顯示提示信息,使用pytest.mark.xfail()
@pytest.mark.xfail()
def test_sum():
random_list = [random.randint(0, 100) for x in range(10)]
num = sum(random_list)
assert num < 20
對(duì)測試用例進(jìn)行多組數(shù)據(jù)測試,每組參數(shù)都能夠獨(dú)立執(zhí)行一次(可以避免測試用例內(nèi)部執(zhí)行單組數(shù)據(jù)測試不通過后停止測試)
@pytest.mark.parametrize('num,num2', [(1,2),(3,4)])
def test_many_odd(num: int, num2: int):
assert num % 2 == 1
assert num2 % 2 == 0
固件(Fixture)
固件就是一些預(yù)處理的函數(shù),pytest會(huì)在執(zhí)行測試函數(shù)前(或者執(zhí)行后)加載運(yùn)行這些固件,常見的應(yīng)用場景就有數(shù)據(jù)庫的連接和關(guān)閉(設(shè)備連接和關(guān)閉)
簡單使用
import pytest
@pytest.fixture()
def postcode():
return "hello"
def test_count(postcode):
assert postcode == "hello"
按照官方的解釋就是當(dāng)運(yùn)行測試函數(shù),會(huì)首先檢測運(yùn)行函數(shù)的參數(shù),搜索與參數(shù)同名的fixture,一旦pytest找到,就會(huì)運(yùn)行這些固件,獲取這些固件的返回值(如果有),并將這些返回值作為參數(shù)傳遞給測試函數(shù);
預(yù)處理和后處理
接下來進(jìn)一步驗(yàn)證關(guān)于官方的說法:
import pytest
@pytest.fixture()
def connect_db():
print("Connect Database in .......")
yield
print("Close Database out .......")
def read_database(key: str):
p_info = {
"name": "zhangsan",
"address": "China Guangzhou",
"age": 99
}
return p_info[key]
def test_count(connect_db):
assert read_database("name") == "zhangsan"執(zhí)行測試函數(shù)結(jié)果:
============================= test session starts =============================
platform win32 -- Python 3.6.8, pytest-6.2.5, py-1.10.0, pluggy-1.0.0 -- D:\Coding\Python3.6\python.exe
cachedir: .pytest_cache
rootdir: C:\Users\libuliduobuqiuqiu\Desktop\GitProjects\PythonDemo\pytest
plugins: Faker-8.11.0
collecting ... collected 1 item
test_example.py::test_count Connect Database in .......
PASSED [100%]Close Database out .......
============================== 1 passed in 0.07s ==============================
備注:
- 首先從結(jié)果上看驗(yàn)證了官方的解釋,pytest執(zhí)行測試函數(shù)前會(huì)尋找同名的固件加載運(yùn)行;
- connect_db固件中有yield,這里pytest默認(rèn)會(huì)判斷yield關(guān)鍵詞之前的代碼屬于預(yù)處理,會(huì)在測試前執(zhí)行,yield之后的代碼則是屬于后處理,將在測試后執(zhí)行;
作用域
從前面大致了解了固件的作用,抽離出一些重復(fù)的工作方便復(fù)用,同時(shí)pytest框架中為了更加精細(xì)化控制固件,會(huì)使用作用域來進(jìn)行指定固件的使用范圍,(比如在這一模塊中的測試函數(shù)執(zhí)行一次即可,不需要模塊中的函數(shù)重復(fù)執(zhí)行)更加具體的例子就是數(shù)據(jù)庫的連接,這一連接的操作可能是耗時(shí)的,我只需要在這一模塊的測試函數(shù)運(yùn)行一次即可,不需要每次都運(yùn)行。
而定義固件是,一般通過scop參數(shù)來聲明作用,常用的有:
- function: 函數(shù)級(jí),每個(gè)測試函數(shù)都會(huì)執(zhí)行一次固件;
- class: 類級(jí)別,每個(gè)測試類執(zhí)行一次,所有方法都可以使用;
- module: 模塊級(jí),每個(gè)模塊執(zhí)行一次,模塊內(nèi)函數(shù)和方法都可使用;
- session: 會(huì)話級(jí),一次測試只執(zhí)行一次,所有被找到的函數(shù)和方法都可用。
import pytest
??
@pytest.fixture(scope="function")
def func_scope():
? ? print("func_scope")
??
@pytest.fixture(scope="module")
def mod_scope():
? ? print("mod_scope")
?
@pytest.fixture(scope="session")
def sess_scope():
? ? print("session_scope")?
?
def test_scope(sess_scope, mod_scope, func_scope):
? ? pass
?
def test_scope2(sess_scope, mod_scope, func_scope):
? ? pass執(zhí)行結(jié)果:
============================= test session starts =============================
platform win32 -- Python 3.6.8, pytest-6.2.5, py-1.10.0, pluggy-1.0.0 -- D:\Coding\Python3.6\python.exe
cachedir: .pytest_cache
rootdir: C:\Users\libuliduobuqiuqiu\Desktop\GitProjects\PythonDemo\pytest
plugins: Faker-8.11.0
collecting ... collected 2 items
test_example2.py::test_scope session_scope
mod_scope
func_scope
PASSED [ 50%]
test_example2.py::test_scope2 func_scope
PASSED [100%]
============================== 2 passed in 0.07s ==============================
從這里可以看出module,session作用域的固件只執(zhí)行了一次,可以驗(yàn)證官方的使用介紹
自動(dòng)執(zhí)行
有人可能會(huì)說,這樣子怎么那么麻煩,unittest框架中直接定義setUp就能自動(dòng)執(zhí)行預(yù)處理,同樣的pytest框架也有類似的自動(dòng)執(zhí)行; pytest框架中固件一般通過參數(shù)autouse控制自動(dòng)運(yùn)行。
import pytest
@pytest.fixture(scope='session', autouse=True)
def connect_db():
print("Connect Database in .......")
yield
print("Close Database out .......")
def test1():
print("test1")
def test2():
print("test")執(zhí)行結(jié)果:
============================= test session starts =============================
platform win32 -- Python 3.6.8, pytest-6.2.5, py-1.10.0, pluggy-1.0.0 -- D:\Coding\Python3.6\python.exe
cachedir: .pytest_cache
rootdir: C:\Users\libuliduobuqiuqiu\Desktop\GitProjects\PythonDemo\pytest
plugins: Faker-8.11.0
collecting ... collected 2 items
test_example.py::test1 Connect Database in .......
PASSED [ 50%]test1
test_example.py::test2 PASSED [100%]test
Close Database out .......
============================== 2 passed in 0.07s ==============================
從結(jié)果看到,測試函數(shù)運(yùn)行前后自動(dòng)執(zhí)行了connect_db固件;
參數(shù)化
前面簡單的提到過了@pytest.mark.parametrize通過參數(shù)化測試,而關(guān)于固件傳入?yún)?shù)時(shí)則需要通過pytest框架中內(nèi)置的固件request,并且通過request.param獲取參數(shù)
import pytest
@pytest.fixture(params=[
('redis', '6379'),
('elasticsearch', '9200')
])
def param(request):
return request.param
@pytest.fixture(autouse=True)
def db(param):
print('\nSucceed to connect %s:%s' % param)
yield
print('\nSucceed to close %s:%s' % param)
def test_api():
assert 1 == 1執(zhí)行結(jié)果:
============================= test session starts =============================
platform win32 -- Python 3.6.8, pytest-6.2.5, py-1.10.0, pluggy-1.0.0 -- D:\Coding\Python3.6\python.exe
cachedir: .pytest_cache
rootdir: C:\Users\libuliduobuqiuqiu\Desktop\GitProjects\PythonDemo\pytest
plugins: Faker-8.11.0
collecting ... collected 2 items
test_example.py::test_api[param0]
Succeed to connect redis:6379
PASSED [ 50%]
Succeed to close redis:6379
test_example.py::test_api[param1]
Succeed to connect elasticsearch:9200
PASSED [100%]
Succeed to close elasticsearch:9200
============================== 2 passed in 0.07s ==============================
這里模擬連接redis和elasticsearch,加載固件自動(dòng)執(zhí)行連接然后執(zhí)行測試函數(shù)再斷開連接。
總結(jié)
對(duì)于開發(fā)來說為什么也要學(xué)習(xí)自動(dòng)化測試這一塊,很重要的一點(diǎn)就是通過自動(dòng)化測試節(jié)省一些重復(fù)工作的時(shí)間,同時(shí)對(duì)于優(yōu)化代碼結(jié)構(gòu),提高代碼覆蓋率,以及后續(xù)項(xiàng)目重構(gòu)都是有著很重要的意義,同時(shí)理解pytest和unittest在基礎(chǔ)上有何區(qū)別有助于不同的業(yè)務(wù)場景中選擇適合自己的測試工具。
這篇文章只是簡單的介紹了pytest的基本使用,有興趣的可以去看看官方文檔,官方文檔中還提到了如內(nèi)置固件的使用,常用測試的場景等等。
到此這篇關(guān)于Pytest 自動(dòng)化測試框架的使用的文章就介紹到這了,更多相關(guān)Pytest 自動(dòng)化測試框架內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
python中HTMLParser模塊知識(shí)點(diǎn)總結(jié)
在本篇文章里小編給大家整理的是一篇關(guān)于python中HTMLParser模塊知識(shí)點(diǎn)內(nèi)容,有興趣的朋友們可以跟著學(xué)習(xí)下。2021-01-01
使用grpc實(shí)現(xiàn)golang后端和python服務(wù)間通信
gRPC是Google 開發(fā)的高性能、開源的遠(yuǎn)程過程調(diào)用(RPC)框架,本文主要為大家詳細(xì)介紹了如何使用grpc實(shí)現(xiàn)golang后端和python服務(wù)間通信,感興趣的可以了解下2024-03-03
Python實(shí)現(xiàn)繪制Matlab格式的地圖邊框的示例代碼
這篇文章主要為大家詳細(xì)介紹了如何利用Python實(shí)現(xiàn)繪制Matlab格式的地圖邊框,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以動(dòng)手嘗試一下2022-09-09
Python中elasticsearch插入和更新數(shù)據(jù)的實(shí)現(xiàn)方法
這篇文章主要介紹了Python中elasticsearch插入和更新數(shù)據(jù)的實(shí)現(xiàn)方法,需要的朋友可以參考下2018-04-04
pycharm運(yùn)行和調(diào)試不顯示結(jié)果的解決方法
今天小編就為大家分享一篇pycharm運(yùn)行和調(diào)試不顯示結(jié)果的解決方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-11-11
通過實(shí)例解析python subprocess模塊原理及用法
這篇文章主要介紹了通過實(shí)例解析python subprocess模塊原理及用法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-10-10
python“靜態(tài)”變量、實(shí)例變量與本地變量的聲明示例
這篇文章主要給大家介紹了關(guān)于python“靜態(tài)”變量、實(shí)例變量與本地變量的聲明的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11
Pycharm?2020最新永久激活碼(附最新激活碼和插件)
最近很多朋友的Pycharm激活時(shí)間又過期了,今天小編再把激活的方法匯總和工具分享一下,文中給大家分享兩種方式,需要的朋友直接拿去用吧2020-01-01
python實(shí)現(xiàn)發(fā)送QQ郵件(可加附件)
這篇文章主要為大家詳細(xì)介紹了python實(shí)現(xiàn)發(fā)送QQ郵件,可添加附件功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-12-12

