前言
pytest默認執行用例是根據項目下的文件名稱按ascii碼去收集運行的;文件中的用例是從上往下按順序執行的。
pytest_collection_modifyitems 這個函數顧名思義就是收集測試用例、改變用例的執行順序的。
【嚴格意義上來說,我們在用例設計原則上用例就不要有依賴順序,這樣才能更好的體現出測試用例的意義。(測試用例的執行不需要按照順序來執行,而是隨即執行)】
1、Hook方法之 pytest_collection_modifyitems :
pytest_collection_modifyitems 是在用例收集完畢之后被調用,可以用來調整測試用例執行順序;
它有三個參數,分別是:
session:會話對象;
config:配置對象;
items:用例對象列表;改變items里面用例的順序就可以改變用例的執行順序了
這三個參數分別有不同的作用,都可以拿來單獨使用,修改用例執行順序主要是使用 items 參數【用例執行之前,收集到的測試用例會以元素對象的方式存放在用例對象列表items中】
2、pytest_collection_modifyitems方法源碼:
def pytest_collection_modifyitems(session, config, items):
""" called after collection has been performed, may filter or re-order the items in-place. :param _pytest.main.Session session: the pytest session object :param _pytest.config.Config config: pytest config object :param List[_pytest.nodes.Item] items: list of item objects """
一、針對單個測試.py文件修改測試用例執行順序
首先准備三個測試用例:
import pytest class TestDemoA: def test_A_001(self): pass def test_A_002(self): pass def test_A_003(self): pass if __name__ == '__main__': pytest.main(['-s'])
正常情況下pytest 會按照從上到下的順序依次執行(模塊級會先以模塊名按ascii編碼進行排序):
使用pytest_collection_modifyitems修改單個測試文件中的用例執行順序
在 conftest.py 文件中 使用pytest_collection_modifyitems 鈎子方法:
# conftest.py # 在收集完測試用例后才會執行 def pytest_collection_modifyitems(items): print('pytest 收集到的所有測試用例:\n',items) if __name__ == '__main__': pytest.main(['-s'])
可以看到控制台中打印出來了收集到的三個測試用例的對象,而且是在測試用例執行之前便已經收集;【先收集測試用例,然后執行測試用例】
在執行完 pytest_collection_modifyitems 之后才顯示收集到了 3 個用例;
如果我們在 pytest_collection_modifyitems 中對用例進行調整,便會影響用例是否執行和執行順序;
利用 items 獲取收集到的用例名和用例節點:
# conftest.py def pytest_collection_modifyitems(items): print('pytest 收集到的所有測試用例:\n', items) for item in items: print('---' * 10) print('用例名:', item.name) print('用例節點:', item.nodeid) if __name__ == '__main__': pytest.main(['-s'])
運行結果:
修改用例執行順序和剔除測試用例:
# conftest.py def pytest_collection_modifyitems(items): # 將用例名拿出來存入新列表new_items new_items = [] for item in items: new_items.append(item.name) # 1. 刪除 test_A_002 用例 # 獲取 test_A_002 在新列表的索引 index_2 = new_items.index('test_A_002') # 在老列表中刪除這個索引 del items[index_2] del new_items[index_2] # 新列表同步刪除,和老列表保持同步 # 2. 調換 1 和 3 的順序 # 獲取 1 和 3 在新列表的索引 index_1 = new_items.index('test_A_001') index_3 = new_items.index('test_A_003') # 根據索引在老列表中調換位置 items[index_1], items[index_3] = items[index_3], items[index_1]
運行結果:
可以看到控制台輸出的結果中,用例3和用例1的順序調換了,用例2由於被刪除所以沒有執行;
代碼寫的比較粗糙,但是思路就是這樣:想辦法干涉 items列表中用例對象的排序;
二、針對多個測試.py文件
pytest默認執行順序
先設計一個簡單的 pytest 項目,有a和b兩個包,分別在 test_a.py 和 test_b.py 寫測試用例
conftest.py內容:
import pytest def pytest_collection_modifyitems(session, items): print("收集到的測試用例:%s"%items)
test_a.py內容:
def test_a_1(): print("測試用例a_1") def test_a_2(): print("測試用例a_2")
test_b.py內容:
def test_b_2(): print("測試用例b_2") def test_b_1(): print("測試用例b_1")
運行完成后可以看到收集到的測試用例【會在測試用例開始執行前收集】:
從結果可以看出運行的時候先按模塊名稱ascii碼去收集,單個py文件里面的用例按從上到下寫的順序收集。
items用例排序
如果我想改變上面的用例執行順序,以所有用例名稱ascii碼排序(測試方法名)。
先獲取到收集的用例的名稱,以用例名稱排序就可以了。
def pytest_collection_modifyitems(session, items): print(type(items)) print("收集到的測試用例:%s" % items) # sort排序,根據用例名稱item.name的ASCII碼排序 items.sort(key=lambda x: x.name) print("排序后的用例:%s" % items) for item in items: print("用例名:%s" % item.name)
重新執行后結果:
重新排序后就可以按用例的名稱ascii碼順序執行了。