使用Marks標記測試用例
通過使用pytest.mark
你可以輕松地在測試用例上設置元數據。例如, 一些常用的內置標記:
- skip - 始終跳過該測試用例
- skipif - 遇到特定情況跳過該測試用例
- xfail - 遇到特定情況,產生一個“期望失敗”輸出
- parametrize - 在同一個測試用例上運行多次調用(譯者注: 參數化數據驅動)
創建自定義標記或將標記應用於整個測試類或模塊很容易。 文檔中包含有關標記的示例,詳情可參閱[使用自定義標記。
注意:
標記只對測試用例有效,對fixtures方法無效。
在未知標記上引發異常: -strict
當使用--strict
命令行參數時,未在pytest.ini
文件中注冊的任何標記都將引發異常。
標記可以通過以下方式注冊:
[pytest]
markers =
slow
serial
這可用於防止用戶意外輸錯標記名稱。 想要強制執行此操作的測試套件應將--strict
添加到addopts
:
[pytest]
addopts = --strict
markers =
slow
serial
標記改造和迭代
3.6版本新函數
pytest的標記傳統地實現是通過簡單地在測試函數的__dict__
中添加屬性來進行標記。結果,標記意外的隨着類的集成而傳遞。此外,使用@pytest.mark
裝飾器應用的標記和通過node.add_marker
添加的標記存儲的位置不同,用於檢索它們的API也
不一致。
這樣,如果不深入了解測試代碼內部結構,技術上幾乎無法正確使用參數化數據,從而導致在高級的使用方法中出現細微且難以理解的bug。
根據標記聲明/更改的方式,你都可以獲得一個MarkerInfo
對象,其中也可能會包含來自同級類的標記。當使用參數化標記,或node.add_marker
時,會丟棄之前的使用裝飾器聲明的MarkDecorators
標記。MarkerInfo
對象實際上是使用同一標記名的多個標記的合並視圖,當然,MarkerInfo
也可以像單個標記一樣使用。
最重要的是,即使標記是在類/模塊上聲明的,實際上,標記只能在函數中訪問。原因是模塊,類和函數/方法無法以相同的方式訪問標記。
在pytest 3.6版本中引入了一個訪問標記的新API,以解決初始設計中的問題,提供_pytest.nodes.Node.iter_markers()方法以一致的方式迭代標記並重新進行內部處理,這很好地解決了初始設計的問題。
升級代碼
不推薦使用原有的Node.get_marker(name)
函數,因為它返回一個內部MarkerInfo
對象,該對象包含應用於該節點的所有標記的合並名稱和所有參數。
通常,有兩種方案可以處理標記:
標記互相覆蓋。 順序很重要,但你只需要將你的標記視為單獨的標記即可。 例如。 對於測試用例中的log_level('debug')
會覆蓋模塊級別的log_level('info')
。
在這種情況下,可以使用Node.get_closest_marker(name)
:
# 替換這個:
marker = item.get_marker("log_level")
if marker:
level = marker.args[0]
# 通過這個:
marker = item.get_closest_marker("log_level")
if marker:
level = marker.args[0]
在特定條件下使用標記。 例如,skipif(condition)
標記,意味着你只想測試所有非condition條件的用例,順序不重要。你可以將這個標記視為一個滿足該條件的集合使用。
在這種情況下,迭代每個標記並單獨處理它們的*args
和**kwargs
參數。
# 替換這個:
skipif = item.get_marker("skipif")
if skipif:
for condition in skipif.args:
# eval condition
...
# 通過這個:
for skipif in item.iter_markers("skipif"):
condition = skipif.args[0]
# eval condition
如果你不確定或遇到任何難題,你可以考慮提出一個待解決問題。
注意:
在未來的Pytest主要版本中,我們將引入基於類的標記,在這些標記處,標記將不再局限於Mark的實例。