pytest中提供的mark
模組,可以實現很多功能,如:
- 標記用例,即打標籤
skip
、skipif
標記跳過,skip
跳過當前用例,skipif
符合情況則跳過當前用例xfail
標記為預期失敗
標記用例
有時候我們可能並不需要執行專案中的所有用例,而只執行其中的某些用例,即指定執行某一類或某個場景的測試用例,比如只執行冒煙用例,那麼這個時候就需要使用@pytest.mark.標籤名
來進行打標籤過濾。標籤名
需要先註冊,然後才能使用。
註冊標籤
官方文件裡提供了三種註冊標籤的方法,這裡只介紹pytest.ini
及conftest.py
,有興趣的可以去檢視官方文件。
方法一,在專案根目錄新建pytest.ini
,並在其中註冊、管理標籤。示例如下:
[pytest]
markers =
smoke: marks test as smoke
login
order: 下單場景
這裡定義了三個標籤,分別是:smoke、login、order,冒號後面的是標籤說明,可不加。
方法二,在conftest.py
中定義鉤子函式進行標籤註冊,格式如下:
def pytest_configure(config):
marker_list = [
"smoke: marks test as smoke",
"login",
"order: 下單場景"
]
for marker in marker_list:
config.addinivalue_line("markers", marker)
方法二需注意定義的格式,不能輕易修改函式名及入參。
使用方法
import pytest
# 標記測試函式
@pytest.mark.smoke
def test_01():
print("執行test_01")
def test_02():
print("執行test_02")
# 標記測試類
@pytest.mark.order
class TestOrder:
def test_order(self):
print("下單")
def test_pay(self):
print("支付")
# 多個標籤
@pytest.mark.smoke
@pytest.mark.login
def test_login():
print("登入")
給測試類打標籤,還有另外一種方式,如下:
# 標記測試類(單個標籤)
class TestOrder:
# 給類中的所有測試方法打上order標籤
pytestmark = pytest.mark.order
def test_order(self):
print("下單")
def test_pay(self):
print("支付")
# 標記測試類(多個標籤)
class TestOrder:
# 給類中的所有測試方法打上order、smoke標籤
pytestmark = [pytest.mark.order, pytest.mark.smoke]
def test_order(self):
print("下單")
def test_pay(self):
print("支付")
同樣可以使用pytestmark
標記模組,給模組中所有的測試類、測試函式打上標籤,如下:
import pytest
# 模組中的所有測試函式、測試類都會被打上order、smoke標籤
pytestmark = [pytest.mark.order, pytest.mark.smoke]
def test_01():
print("執行test_01")
def test_02():
print("執行test_02")
class TestOrder:
def test_order(self):
print("下單")
def test_pay(self):
print("支付")
執行方法
執行的時候加上引數-m
加標籤名
即可。
命令列:
# 執行被標記為smoke的用例
pytest -m smoke
# 執行被標記為smoke且被標記為login的用例
pytest -m "smoke and login"
# 執行被標記為smoke或login的用例
pytest -m "smoke or login"
程式碼執行:
# 執行被標記為smoke的用例
pytest.main(['-m smoke'])
# 執行被標記為smoke或order的用例
pytest.main(["-m", "smoke or order"])
# 執行被標記為smoke同時被標記為login的用例
pytest.main(["-m", "smoke and login"])
# 執行被標記為smoke且不被標記為login的用例
pytest.main(["-m", "smoke and not login"])
這裡需要注意,在測試模組中直接使用pytest.main()
執行當前模組中的被打標籤的用例是無效的,這樣會執行當前模組中的所有測試用例。如下示例:
import pytest
# 標記測試函式
@pytest.mark.smoke
def test_01():
print("執行test_01")
def test_02():
print("執行test_02")
# 標記測試類
@pytest.mark.order
class TestOrder:
def test_order(self):
print("下單")
def test_pay(self):
print("支付")
# 多個標籤
@pytest.mark.smoke
@pytest.mark.login
def test_login():
print("登入")
if __name__ == '__main__':
pytest.main(['-s', '-m smoke'])
執行該模組,結果如下:
從結果中可以看出,雖然程式碼中寫了只執行標記為smoke
的用例,但所有5條用例都被執行了,不能進行過濾。
我們需要將執行程式碼分離出來,放在單獨的執行模組裡面,如放在run.py
裡,程式碼如下:
# run.py
import pytest
if __name__ == '__main__':
pytest.main(["-s", "-m", "smoke or order"])
執行結果如下:
從結果可以看出來,這裡只執行了標記為smoke
或order
的測試用例。
標記跳過
有時候我們需要跳過某些測試用例不去執行,如程式碼更新後老的用例不需要執行了,或者在某些特定場景下不需要執行某些用例,這時就需要給對應的測試用例做標記跳過處理。
pytest中提供了兩種標記跳過的方法,如下:
- 直接跳過,
@pytest.mark.skip(reason="跳過原因")
,reason可寫可不寫。 - 條件跳過,即滿足某個條件則跳過不執行,
@pytest.mark.skipif(b>3, reason="跳過原因")
示例如下:
import pytest
@pytest.mark.skip(reason="不需要執行test_01")
def test_01():
print("執行test_01")
@pytest.mark.skip(2>1, reason="如果2大於1則跳過不執行")
def test_02():
print("執行test_02")
if __name__ == '__main__':
pytest.main(['-s'])
執行結果:
從執行結果中可以看到,這2條用例都被跳過。如果想要 跳過測試類 或 測試模組,方法同上面給測試類、測試模組打標籤的方法一樣,不做過多說明。
xfail(標記為預期失敗)
有些場景下需要將測試用例標記為預期失敗,如對尚未實現的功能或尚未修復的錯誤進行測試,使用@pytest.mark.xfail
可以將測試用例標記為預期失敗。
pytest.mark.xfail(condition=None, reason=None, raises=None, run=True, strict=False)
,引數說明如下:
-
condition
,預期失敗的條件,預設值為None,表示只有滿足條件時才標記用例為預期失敗。 -
reason
,失敗原因,預設值為None,說明標記用例的原因。 -
strict
關鍵字引數,預設值為False。當 strict=False 時,如果用例執行失敗,則結果標記為
xfail
,表示符合預期的失敗;如果用例執行成功,結果標記為XPASS,表示不符合預期的成功;當strict=True時,如果用例執行成功,結果將標記為failed。
-
raises
關鍵字引數,預設值為None,可以上報指定的一個或多個異常。如果用例的失敗不是因為所期望的異常導致的,pytest將會把測試結果標記為failed。 -
run
關鍵字引數,預設值為True。當run=False時,pytest不會再執行測試用例,直接將結果標記為xfail。
常用的引數示例如下:
import pytest
# run、strict都為預設,因為用例執行是失敗的,所以該用例執行結果會被標記為xfail
@pytest.mark.xfail(reason="bug待修復")
def test_01():
print("執行test_01")
a = "hello"
b = "hi"
assert a == b
# run、strict都為預設,因為用例執行是通過的,所以該用例執行結果會被標記為xpass
@pytest.mark.xfail(condition=lambda: True, reason="bug待修復")
def test_02():
print("執行test_02")
a = "hello"
b = "hi"
assert a != b
# run=False,該用例不執行,直接將結果標記為xfail
@pytest.mark.xfail(reason="功能尚未開發完成", run=False)
def test_03():
print("執行test_03")
a = "hello"
b = "hi"
assert a == b
# strict=True,因為用例執行是通過的,所以結果會被標記為failed
@pytest.mark.xfail(reason="功能尚未開發完成", strict=True)
def test_04():
print("執行test_04")
a = "hello"
b = "he"
assert b in a
if __name__ == '__main__':
pytest.main(['-s'])
執行結果:
從結果中可以看出來,test_01
結果展示為xfail
,test_02
結果展示為xpass
,test_03
沒有執行而是直接展示為xfail
,test_04
結果展示為failed
總結
以上示例僅僅只是為了說明@pytest.mark
提供的這些功能的使用方法,實際自動化過程中需要靈活選用。
在一般的自動化測試過程中,通過打標籤的方式標記某個場景用例會比較多,如標記冒煙測試用例用於冒煙測試。跳過或條件跳過測試用例也經常會用到。而需要將用例標記為預期失敗的場景則比較少。