pytest進階使用
3. pytest進階使用
3.1 命令列引數
3.1.1 執行引數
Pytest的執行有很多引數,使用幫助檢視:
pytest -h
常用引數:
引數 | 說明 |
---|---|
-v | 可以輸出用例更加詳細的執行資訊,比如用例所在的檔案及用例名稱 |
-s | 輸入我們用例中的調式資訊,比如print的列印資訊等 |
-x | 遇到失敗的用例立即停止 |
-maxfail | 用例失敗達到一定個數時停止執行pytest --maxfail=num |
-m | 執行有@pytest.mark.標記名 的測試用例 |
-k | 選擇部分測試,匹配給出的表示式;eg: pytest -k “raises and not delete”(執行所有名字中包含 raises但不包含delete的測試) |
–collect-only | 只收集用例 |
pytest -sv test_demo.py
3.1.2 Mark標籤
可以對測試用例打標籤,在執行測試用例的時候,可根據標籤名來過濾要執行的用例
方式:在測試用例/測試類前加上:@pytest.mark.標記名
import pytest
class Test_Demo():
@pytest.mark.demo
def test_demo(self):
a = 5
b = -1
assert a != b
print("我的第一個測試用例")
@pytest.mark.smoke
def test_two(self):
a = 2
b = -1
assert a != b
print("我的第二個測試用例")
也可以在一個用例上打多個標籤,多次使用@pytest.mark.標籤名
@pytest.mark.demo
@pytest.mark.smoke
def test_add_02():
b = 1 + 2
assert 0 == b
執行:
pytest -m 標籤名
註冊標籤消除執行warning:
- 建立pytest.ini檔案,在檔案中按如下方式新增標籤名:
[pytest]
markers = demo
smoke
3.2 資料驅動入門
3.2.1 引數化
在測試用例的前面加上:
@pytest.mark.parametrize("引數名",列表資料)
- 引數名:作為測試用例的引數. 字串格式,多個引數中間用逗號隔開。
- 列表資料:一組測試資料。list格式,多組資料用元組型別,list的每個元素都是一個元組,元組裡的每個元素和按引數順序一一對應。
3.2.2 引數化演練
import pytest
def add_function(a,b):
return a+b
@pytest.mark.parametrize("a,b,expected",
[(3,5,8),
(-1,-2,-3),
(100,200,300),
])
def test_add(a,b,expected):
assert add_function(a,b) == expected
3.2.3 引數加別名
pytest執行後,會使用輸入資料來作為用例的標題,但是這樣不便於我們檢視。可以新增ids引數指定用例說明。
import pytest
def add_function(a,b):
return a+b
@pytest.mark.parametrize("a,b,expected",
[(3,5,8),
(-1,-2,-3),
(100,200,300),
],ids=["int","minus","bigint"])
def test_add(a,b,expected):
assert add_function(a,b) == expected
3.2.4 引數組合
若要獲得多個引數化引數的所有組合,可以堆疊引數化裝飾器
import pytest
@pytest.mark.parametrize("a", [0, 1])
@pytest.mark.parametrize("b", [2, 3])
def test_foo(a, b):
print("測試資料組合:a->%s, b->%s" % (a, b))
執行結果
test_demo.py::test_foo[2-0] 測試資料組合:a->0, b->2 PASSED
test_demo.py::test_foo[2-1] 測試資料組合:a->1, b->2 PASSED
test_demo.py::test_foo[3-0] 測試資料組合:a->0, b->3 PASSED
test_demo.py::test_foo[3-1] 測試資料組合:a->1, b->3 PASSED
3.2.5 使用yaml檔案實現用例資料引數化
注意:使用之前需要在pycharm中安裝PyYAML
載入yaml檔案:
yaml.safe_load(open("./data.yml"))
import pytest
import yaml
def add_function(a,b):
return a+b
@pytest.mark.parametrize("a,b,expected",
yaml.safe_load(open("./data.yml"))["datas"],
ids=yaml.safe_load(open("./data.yml"))["myid"])
def test_add(a,b,expected):
assert add_function(a,b) == expected
data.yml檔案:
datas:
-
- 3
- 5
- 8
-
- -1
- -2
- -3
-
- 100
- 200
- 300
myid:
- "int"
- "minus"
- "bigint"
讀取資料抽離出來改造:
import pytest
import yaml
def get_datas():
with open("./data.yml") as f:
datas = yaml.safe_load(f)
print(datas)
add_datas=datas["datas"]
add_ids=datas["myid"]
return [add_datas,add_ids]
def add_function(a,b):
return a+b
@pytest.mark.parametrize("a,b,expected",
get_datas()[0],
ids=get_datas()[1])
def test_add(a,b,expected):
assert add_function(a,b) == expected
3.2.6 使用yaml檔案實現用例步驟引數化
steps.yml
- step1
- step2
- step3
import pytest
import yaml
def step1():
print("開啟瀏覽器")
def step2():
print("註冊新賬號")
def step3():
print("登入新賬號")
# 解析測試步驟檔案
def steps(path):
with open(path) as f:
steps = yaml.safe_load(f)
for step in steps:
if "step1" in step:
step1()
elif "step2" in step:
step2()
elif "step3" in step:
step3()
def test_foo():
steps("./steps.yml")
https://github.com/ceshiren/HogwartsSDET12/blob/master/appium_xueqiu/page/base_page.py1
3.3 fixture裝置的使用
3.3.1 fixture使用背景
前面講了setup、teardown可以實現在執行用例前或結束後加入一些操作,但這種都是針對整個指令碼全域性生效的。(註釋:setup相當於這個個檔案使用,每個檔案裡用;fixtire是對每個用例)
如果有以下場景:用例 1 需要先登入,用例 2 不需要登入,用例 3 需要先登入。很顯然無法用 setup 和 teardown 來實現。fixture可以讓我們自定義測試用例的前置條件,並且可以跨檔案使用。
3.3.2 fixture的優勢
- 命名方式靈活,不侷限於 setup 和teardown 這幾個命名
- conftest.py 配置裡可以實現資料共享,不需要 import 就能自動找到fixture
- scope=“session” 以實現多個.py跨檔案共享
3.3.3@pytest.fixtrue()快速體驗
- 直接使用
import pytest
@pytest.fixture()
def myfixture():
print("執行myfixture")
class Test_firstFile():
def test_one(self):
print("執行test_one")
assert 2+3==5
def test_two(self,myfixture):
print("執行test_two")
assert 1==1
def test_three(self):
print("執行test_three")
assert 1+1==2
- 通過conftest.py檔案
conftest.py這個檔名是固定的,不可以更改。
使用的時候不需要匯入conftest.py,會自動尋找.
演練:建立一個conftest.py檔案
import pytest
@pytest.fixture()
def myfixture():
print("執行myfixture")
###3.3.4 fixture中使用autouse
如果我們想要模組中每個測試函式都是用宣告好的前置函式,每個測試函式都傳入引數或新增裝飾器,是不是很不方便?這時我們可以使用@pytest.fixture()中的引數autouse(自動使用),將其設為true(預設為false),這樣每個測試函式都會自動呼叫該前置函數了。
語法:
@pytest.fixture(autouse="true")
3.3.5 fixture中使用作用域
語法:
@pytest.fixture(scope ="class")
scope引數有四種選擇:function(測試函式級別),class(測試類級別),module(測試模組“.py”級別),session(多個檔案級別)。預設是function級別。
3.3.6 fixture中使用引數
fixture函式可以引數化,在這種情況下,它們將被多次呼叫,每次執行一組相關測試,即依賴於這個fixture的測試,測試函式通常不需要知道它們的重新執行。
fixture函式需要傳入特殊的request物件
函式裡面可通過request.param訪問每個引數的值
也可加ids指定引數名字
import pytest
@pytest.fixture(params=["引數1","引數2"])
def myfixture(request):
print("執行testPytest裡的前置函式,%s" % request.param)
3.3.7 fixture中返回引數
import pytest
@pytest.fixture(params=["引數1","引數2"])
def myfixture(request):
return request.param
def test_print_param(myfixture):
print("執行test_two")
print(myfixture)
assert 1==1
輸出:
PASSED [ 50%]執行test_two
引數1
PASSED [100%]執行test_two
引數2
3.3.8 fixture中使用yield實現teardown
fixture裡面的teardown用yield來喚醒teardown的執行
import pytest
@pytest.fixture(params=["引數1","引數2"])
def connect_db(request):
print("開始連線資料庫!")
yield request.param
print("執行teardown,關閉資料庫連線")
def test_print_param(connect_db):
print("執行test_two")
print(connect_db)
assert 1==1
3.4 給pytest.ini新增更多配置
[pytest]
markers = demo
smoke
addopts = -sv
;自定義測試檔案命名規則
python_files = check*
;自定義測試類命名規則
python_classes = Test*
;自定義測試方法命名規則
python_functions = test_* check_*
4 pytest實用外掛介紹
可在這裡搜尋使用方式:
##4.1. 用例失敗後自動重新執行:pytest-rerunfailures
安裝外掛:
pip install pytest-rerunfailures
使用方法:
pytest test_x.py --reruns=n #失敗後重執行的次數
同時也可以在指令碼中指定定義重跑的次數,這個時候在執行的時候,就無需加上 --reruns 這個引數
@pytest.mark.flaky(reruns=6, reruns_delay=2)
def test_example(self):
print(3)
assert random.choice([True, False])
4.2 多重校驗:pytest-assume
pytest中可以用python的assert斷言,也可以寫多個斷言,但一個失敗,後面的斷言將不再執行。
安裝外掛:
pip install pytest-assume
使用方法:
def test_simple_assume(x, y):
pytest.assume(x == y)
pytest.assume(True)
pytest.assume(False)
4.3 分散式併發執行:pytest-xdist
pytest-xdist的出現就是為了讓自動化測試用例可以分散式執行,從而節省自動化測試時間
分散式執行用例的設計原則:
- 用例之間是獨立的,用例之間沒有依賴關係,用例可以完全獨立執行【獨立執行】
- 用例執行沒有順序,隨機順序都能正常執行【隨機執行】
- 每個用例都能重複執行,執行結果不會影響其他用例【不影響其他用例】
安裝外掛:
pip install pytest-xdist
使用方法:
多cpu並行執行用例,直接加個-n引數即可,後面num引數就是並行數量,比如num設定為3
pytest -n 3
4.4 控制用例的執行順序:pytest-ordering
安裝外掛:
pip install pytest-ordering
使用方法:
import pytest
@pytest.mark.run(order=2)
def test_foo():
assert True
@pytest.mark.run(order=1)
def test_bar():
assert True
注意:儘量不要讓測試用例有順序,儘量不要讓測試用例有依賴!
4.5 hook(鉤子)函式定製和擴充套件外掛【瞭解】
官網:https://docs.pytest.org/en/latest/_modules/_pytest/hookspec.html
pytest_collection_modifyitems
Pytest在收集完所有測試用例後呼叫該鉤子方法。我們可以定製化功能實現:
- 自定義用例執行順序
- 解決編碼問題(中文測試用例名稱)
- 自動新增標籤
例如:
conftest.py裡面:
新增:
def pytest_collection_modifyitems(session, config, items):
print(type(items))
items.reverse()
for item in items:
item.name = item.name.encode('utf-8').decode('unicode-escape')
item._nodeid = item.nodeid.encode('utf-8').decode('unicode-escape')
if "add" in item._nodeid:
item.add_marker(pytest.mark.add)
if "div" in item._nodeid:
item.add_marker(pytest.mark.div)
5 Allure
安裝:https://repo.maven.apache.org/maven2/io/qameta/allure/allure-commandline/2.13.7/
- mac直接
brew install allure
安裝 - windows直接下載zip包,解壓後把bin路徑配置到path裡面,使用allure.bat
- 命令列輸入allure檢視安裝是否成功。
pytest裡面安裝allure-pytest
使用allure:
pytest --alluredir ./report
生成的result記錄詳細結果,中間結果。最終結果:
allure serve ./report
起了一個服務,後續會進階學習。
暫時服務,長期服務用jenkins,或者在本地搭建網站服務:Django。
python mange.py runserver (http://127.0.0.1:8000)
生成html檔案:
allure generate ./report
生成html檔案,open in chrome