柚子快報邀請碼778899分享:Pytest
柚子快報邀請碼778899分享:Pytest
1、pytest安裝
# windows
pip install pytest
-i
https://pypi.douban.com/simple
# mac
python3
-m
pip install pytest
-i
https://pypi.douban.com/simple
2、命名測試文件規(guī)則
文件名以
test_*.py
文件和
*_test.py
測試用例規(guī)則
在
pytest
中編寫測試用例可以以兩種方式編寫
1. 純函數(shù)式
以
test_
開頭的函數(shù)
def test_login_success():
resp = login(userName="admin", password="1234")
status_code = resp.status_code
assert status_code == 200
code = resp.json()["code"]
assert code == "0"
2. 以類的方式
以
Test
開頭的類,不能包含
init
方法
在類里以
test_
開頭的方法代表一條用例
class TestBuyerLogin:
def test_buyer_login(self):
resp = buyer_login(username="Chronos",password="e10adc3949ba59abbe56e057f20f883e")
assert resp.json()["uid"]==61253
assert resp.json()["username"] == "Chronos"
3.pytest參數(shù)化(數(shù)據(jù)驅(qū)動)
當(dāng)我們的多個用例除了測試數(shù)據(jù)和期望結(jié)果不同,其他的代碼都高度相似時,我們可以使用參數(shù)化的方式優(yōu)化用例編寫
首先整理數(shù)據(jù) ?下文中的 test_data
使用裝飾器引入數(shù)據(jù)
@pytest.mark.parametrize("userName,password,expect_code,expect_message,expect_json", test_data)
編寫測試用例,傳入測試數(shù)據(jù)
test_data = [["Chronos", "123456asdf", "0", "success", {'code': '0', 'message': 'success', 'data': None}],
["", "123456asdf", "1", "參數(shù)為空", {'code': '1', 'message': '參數(shù)為空', 'data': None}],
["Chronos", "", "1", "參數(shù)為空", {'code': '1', 'message': '參數(shù)為空', 'data': None}]]
# 使用裝飾器引入數(shù)據(jù)據(jù)
@pytest.mark.parametrize("userName,password,expect_code,expect_message,expect_json", test_data)
def test_login(userName, password, expect_code, expect_message, expect_json):
resp = login(userName=userName, password=password)
status_code = resp.status_code
code = resp.json()["code"]
message = resp.json()["message"]
assert message == expect_message
assert status_code == 200
assert expect_json == resp.json()
assert code ==expect_code
4.pytest笛卡爾積參數(shù)化(數(shù)據(jù)驅(qū)動)
cliebt_data = ['PC', 'WAP', 'NATIVE', 'REACT', 'MINI']
way_data = ['BUY_NOW', 'CART']
@pytest.mark.parametrize("client", cliebt_data)
@pytest.mark.parametrize("way", way_data)
class TestCreateTrade:
def test_create_trade(self, client, way):
buyer_login(username="Chronos", password="e10adc3949ba59abbe56e057f20f883e")
if way == 'BUY_NOW':
buy_now()
elif way == 'CART':
add_cart()
resp = create_trade(client=client, way=way)
assert resp.status_code == 200
5、pytest前置后置處理器
1. 模塊級別:
setup_module
、
teardown_module
setup_module
:在每個模塊執(zhí)行前執(zhí)行
teardown_module
:在每個模塊執(zhí)行后執(zhí)行
2. 函數(shù)級別
setup_function
、
teardown_function
,不在類中的方法
setup_function
:在每個函數(shù)執(zhí)行前執(zhí)行
teardown_function
:在每個函數(shù)執(zhí)行后執(zhí)行
有幾個函數(shù)就會執(zhí)行幾次
3. 類級別:
setup_class
、
teardown_class
setup_class
:在每個類執(zhí)行前執(zhí)行
teardown_class
:在每個類執(zhí)行后執(zhí)行
有幾個類就有幾對
4. 方法級別:
setup_method
、
teardown_method
setup_method
:在類里面的每個方法執(zhí)行前執(zhí)行
teardown_method
:在類里面每個方法執(zhí)行后執(zhí)行
6、pytest fixture函數(shù)
# 自定義fixture的@pytest.fixture重點(diǎn)參數(shù)
"""
scope: 該fixture函數(shù)的作用域,不指定時默認(rèn)就是function
scope參數(shù)的值有以下幾種:
1.session: 指的pytest的session,一次pytest執(zhí)行就是一個session,在當(dāng)前session該fixture函數(shù)只會被執(zhí)行一次
2.package: 在一個包下,該fixture函數(shù)只會被執(zhí)行一次
3.module: 在一個模塊中,該fixture不管被調(diào)用多少次,只會被執(zhí)行一次
4.class: 在一個類中,該fixture不管被調(diào)用多少次,只會被執(zhí)行一次
5.function: 在一個函數(shù)或者方法中,該fixture不管被調(diào)用多少次,只會被執(zhí)行一次
"""
"""
autouse: 表示該fixture是否被自動調(diào)用執(zhí)行,默認(rèn)是False
autouse=False時,我們需要主動調(diào)用fixture他才會被執(zhí)行
主動調(diào)用有兩種:
1.使用裝飾器,@pytest.mark.usefixtures('buyer_login_fixture')
2.可以在測試用例函數(shù)中作為參數(shù)傳遞
"""
@pytest.fixture(scope='package',autouse=True)
def buyer_login_fixture():
buyer_login('shamo', 'e622fdb8f36d56d96d8cf815d72112cb')
print('執(zhí)行fixture函數(shù)')
7、conftest.py和fixture
我們將自定義的
fixture
放在測試文件中,這樣的話會比較混亂。為了統(tǒng)一管理自定義的
fixture
,我們可
以把他們放在
conftest.py
文件中。
conftest.py
是
pytest
測試框架的一個特殊文件,名稱是固定的,他可以被用來管理自定義
fixture
,也可
以用來重寫
pytest
的一些鉤子函數(shù)。這個文件在一個項目可以有多個在不同的包下,在自己的包下生
效。但是我們建議一個項目用一個就行。在
pytest
執(zhí)行時,會自動掃描
contest
里的代碼,根據(jù)各個函數(shù)
定義的規(guī)則進(jìn)行執(zhí)行。
1、在conftest.py中定義前后置
@pytest.fixture(scope='session',autouse=False)
def buyer_login_fixture():
buyer_login()
print('執(zhí)行fixture函數(shù)')
yield # yield的下一行表示后置處理
print('用例執(zhí)行完成了,退出登錄')
# fixture還可以實現(xiàn)數(shù)據(jù)返回
@pytest.fixture(scope='session',autouse=False)
def get_token():
resp = buyer_login()
buyer_token = resp.json()['access_token']
print('執(zhí)行fixture函數(shù)')
yield buyer_token# yield的下一行表示后置處理
# return buyer_token 這種返回也行,但是他不支持后置處理
print('用例執(zhí)行完成了,退出登錄')
2、解決標(biāo)題中文亂碼
# 使用自定義fixtrue實現(xiàn)數(shù)據(jù)處理并返回
def pytest_collection_modifyitems(
session: "Session", config: "Config", items: List["Item"]
) -> None:
# item表示每個測試用例,解決用例名稱中文顯示問題
for item in items:
item.name = item.name.encode("utf-8").decode("unicode-escape")
item._nodeid = item._nodeid.encode("utf-8").decode("unicode-escape")
8、失敗重試
安裝插件
# windows
pip3 install pytest-rerunfailures -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com
# mac
python3
-
m pip install pytest
-
rerunfailures
-
i
https
:
//
pypi
.
douban
.
com
/
simple
如何使用
1. 使用命令行參數(shù)
是一種全局性的指定,意味執(zhí)行所有的用例都遵循這個失敗重試的規(guī)則
--reruns 3
指的是最大重試次數(shù),本身失敗,如果第
1次重試成功了,后面兩次不會執(zhí)行
--reruns-delay 5
如果想在重試間隔中有延遲,可以加這個參數(shù),單位是秒
pytest -sv --reruns 3 pytest_study\test_buy_now_api.py
2. 裝飾器指定
可以用于指定特定的用例失敗重試的次數(shù),
reruns_delay=10
表示每次重試的時間延遲,單位是秒
@pytest.mark.flaky(reruns=2,reruns_delay=10)
9.多斷言插件
在之前的接口用例里,有的接口存在著多個斷言,我們一律使用了
assert
assert
斷言一旦失敗,用例即可結(jié)束,后續(xù)的斷言不會被執(zhí)行到。那這可能不是我們所希望的,我們希
望把所有斷言都執(zhí)行到,暴露出更多的問題。
有一個
pytest-assume
的插件,可以提供這種多斷言的方式,他的斷言在失敗后不會結(jié)束用例執(zhí)行,而
是把所有斷言執(zhí)行完成后才結(jié)束,只要有一個失敗那么這條用例就失敗
安裝插件
# windows
pip install pytest-assume
-i
https://pypi.douban.com/simple
# mac
python3
-m
pip install pytest-assume
-i
https://pypi.douban.com/simple
使用方法
pytest.assume(期待結(jié)果,描述)
def test_login_password_null():
resp = login(userName="Chronos", password="")
status_code = resp.status_code
code = resp.json()["code"]
pytest.assume(code == "1", f'期望值是0,實際值是{code}')
pytest.assume(status_code == 200, f'期望值是200,實際值是{status_code}')
10.重復(fù)執(zhí)行
安裝插件
# windows
pip install pytest-repeat
-i
https://pypi.douban.com/simple
# mac
python3
-m
pip install pytest-repeat
-i
https://pypi.douban.com/simple
1. 命令行參數(shù)
--count 5
表示重復(fù)
5
次
pytest -sv --count 5 pytest_study\test_buy_now_api.py
2. 裝飾器指定
里邊的數(shù)字代表重復(fù)的次數(shù)。
@pytest.mark.repeat(2)
11.allure測試報告
安裝插件
# windows
pip install allure-pytest
-i
https://pypi.douban.com/simple
# mac
python3
-m
pip install allure-pytest
-i
https://pypi.douban.com/simple
如何使用:
1. 命令行參數(shù)用來收集測試結(jié)果數(shù)據(jù)
在命令行先進(jìn)入到
pytest_study
目錄下,執(zhí)行下述命令
--alluredir ./report/data
表示收集到的測試結(jié)果數(shù)據(jù)會存入
report/data
目錄下
--clean-alluredir
表示每次執(zhí)行都清除之前的數(shù)據(jù)
pytest -sv --alluredir ./report/data --clean-alluredir
2. 使用allure報告生成的工具生成html報告
下載
allure-2.11.0.zip
文件,然后解壓,配環(huán)境變量,將
D:\allure-2.11.0\bin
配到
path
,
根據(jù)自己的解壓路徑來
重開命令行驗證
allure
--version
如果提示不是內(nèi)部命令,要么你命令敲錯了,要么你環(huán)境變量配的不對
如果提示
java_home
不對,說明你電腦沒裝
jdk
,或者
java_home
配的不對,那就要按照
jdk
或者檢
查
java
環(huán)境變量
重啟
pycharm
在
pycharm
終端執(zhí)行下述命令
在命令行先進(jìn)入到
pytest_study
目錄下,執(zhí)行下述命令
report/data
指的是你的測試結(jié)果數(shù)據(jù)目錄,就是第
1
步生成的
allure serve report/data
12.整體執(zhí)行入口及pytest.ini文件
[pytest]
addopts = -sv --alluredir ./report/data --clean-alluredir
testpaths = ./
python_files = test_*.py
python_classes = Test*
python_functions = test_*
addopts:
指定
pytest
執(zhí)行時的命令行參數(shù)
testpaths
:指的是要執(zhí)行的目錄,
./
表示當(dāng)前目錄
python_files
:指的是要執(zhí)行的測試文件,或者測試文件命名規(guī)則
python_classes
:指定的要執(zhí)行的測試類,或者測試類命名規(guī)則
python_functions
:指定的要執(zhí)行的測試方法或者測試函數(shù),或者他們的命名規(guī)則
在
pytest_study
目錄下創(chuàng)建
run.py
,該文件作為整體執(zhí)行入口出現(xiàn)
import os
import pytest
if __name__ == '__main__':
# pytest.main() 會自動掃描pytest.ini的配置
pytest.main()
# 執(zhí)行完成后自動打開報告 僅用于本地調(diào)試
os.system('allure serve report/data')
13.allure測試報告層級劃分
為了能夠更好的在測試報告上展示我們的用例,我們可以針對用例按照一定的維度進(jìn)行分類管理
@allure.epic('買家服務(wù)')
@allure.feature('交易模塊')
@allure.story('創(chuàng)建交易接口用例')
@pytest.mark.usefixtures('buyer_login_fixture')
class TestCreateTrade:
client_data = ['PC', 'WAP', 'NATIVE', 'REACT', 'MINI'] # 5個數(shù)據(jù)
way_data = ['BUY_NOW', 'CART'] # 2個數(shù)據(jù)
@pytest.mark.parametrize('client', client_data)
@pytest.mark.parametrize('way', way_data)
def test_create_trade(self, client, way, buyer_login_fixture): # 生成的數(shù)據(jù)總數(shù)是5*2=10
allure.dynamic.title(f'{client}-{way}')
# buyer_login('shamo','e622fdb8f36d56d96d8cf815d72112cb')
# buyer_token = resp.json()['access_token']
# 如果way是BUY_NOW就調(diào)用立即購買接口
# 如果way是CART就調(diào)用添加購物車接口
if way == 'BUY_NOW':
buy_now(sku_id=541, num=1)
elif way == 'CART':
add_cart(sku_id=541, num=1)
resp = create_trade(client=client, way=way)
assert resp.status_code == 200
柚子快報邀請碼778899分享:Pytest
參考閱讀
本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點(diǎn)和立場。
轉(zhuǎn)載請注明,如有侵權(quán),聯(lián)系刪除。