pytest(9)-標記用例(指定執行、跳過用例、預期失敗)

給你一頁白紙發表於2022-02-18

pytest中提供的mark模組,可以實現很多功能,如:

  1. 標記用例,即打標籤
  2. skipskipif標記跳過,skip跳過當前用例,skipif符合情況則跳過當前用例
  3. xfail標記為預期失敗

標記用例

有時候我們可能並不需要執行專案中的所有用例,而只執行其中的某些用例,即指定執行某一類或某個場景的測試用例,比如只執行冒煙用例,那麼這個時候就需要使用@pytest.mark.標籤名來進行打標籤過濾。標籤名需要先註冊,然後才能使用。

註冊標籤

官方文件裡提供了三種註冊標籤的方法,這裡只介紹pytest.iniconftest.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"])

執行結果如下:

從結果可以看出來,這裡只執行了標記為smokeorder的測試用例。

標記跳過

有時候我們需要跳過某些測試用例不去執行,如程式碼更新後老的用例不需要執行了,或者在某些特定場景下不需要執行某些用例,這時就需要給對應的測試用例做標記跳過處理。

pytest中提供了兩種標記跳過的方法,如下:

  1. 直接跳過,@pytest.mark.skip(reason="跳過原因"),reason可寫可不寫。
  2. 條件跳過,即滿足某個條件則跳過不執行,@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),引數說明如下:

  1. condition,預期失敗的條件,預設值為None,表示只有滿足條件時才標記用例為預期失敗。

  2. reason,失敗原因,預設值為None,說明標記用例的原因。

  3. strict關鍵字引數,預設值為False。

    當 strict=False 時,如果用例執行失敗,則結果標記為xfail,表示符合預期的失敗;如果用例執行成功,結果標記為XPASS,表示不符合預期的成功;

    當strict=True時,如果用例執行成功,結果將標記為failed。

  4. raises關鍵字引數,預設值為None,可以上報指定的一個或多個異常。如果用例的失敗不是因為所期望的異常導致的,pytest將會把測試結果標記為failed。

  5. 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結果展示為xfailtest_02結果展示為xpasstest_03沒有執行而是直接展示為xfailtest_04結果展示為failed

總結

以上示例僅僅只是為了說明@pytest.mark提供的這些功能的使用方法,實際自動化過程中需要靈活選用。

在一般的自動化測試過程中,通過打標籤的方式標記某個場景用例會比較多,如標記冒煙測試用例用於冒煙測試。跳過或條件跳過測試用例也經常會用到。而需要將用例標記為預期失敗的場景則比較少。

相關文章