前言
通常我們認為每個測試用例都是相互獨立的,因此需要保證測試結果不依賴於測試順序,以不同的順序運行測試用例,可以得到相同的結果。
pytest默認運行用例的順序是按模塊和用例命名的 ASCII 編碼順序執行的,這就意味着每次運行用例的順序都是一樣的。
app 測試里面有個 monkey 測試,隨機在頁面點點點,不按常理的點點點能找到更多的不穩定性 bug。那么我們在寫pytest用例的時候,既然每個用例都是相互獨立的,
那就可以打亂用例的順序隨機執行,用到 pytest 的插件 pytest-random-order 可以實現此目的,github 地址https://github.com/jbasko/pytest-random-order
pytest-random-order 插件
pytest-random-order是一個pytest插件,用於隨機化測試順序。這對於檢測通過的測試可能是有用的,因為該測試恰好在不相關的測試之后運行,從而使系統處於良好狀態。
該插件允許用戶控制他們想要引入的隨機性級別,並禁止對測試子集進行重新排序。通過傳遞先前測試運行中報告的種子值,可以按特定順序重新運行測試。

使用pip安裝
pip install pytest-random-order
在pytest -h查看,命令行可以有三個參數選擇
pytest-random-order options:
--random-order Randomise test order (by default, it is disabled) with default configuration.
--random-order-bucket={global,package,module,class,parent,grandparent,none}
Randomise test order within specified test buckets.
--random-order-seed=RANDOM_ORDER_SEED
Randomise test order using a specific seed.
從v1.0.0開始,默認情況下,此插件不再將測試隨機化。要啟用隨機化,您必須以下列方式之一運行pytest:
pytest --random-order
pytest --random-order-bucket=<bucket_type>
pytest --random-order-seed=<seed>
如果要始終隨機化測試順序,請配置pytest。有很多方法可以做到這一點,我最喜歡的一種方法是addopts = --random-order在pytest選項(通常是[pytest]或[tool:pytest]部分)下添加特定於項目的配置文件。
# pytest.ini文件內容
[pytest]
addopts = --random-order
--random-order 隨機測試
先寫幾個簡單的用例,目錄結構如下

module1/test_order1.py內容
# module1/test_order1.py
# 作者-上海悠悠 QQ交流群:717225969
# blog地址 https://www.cnblogs.com/yoyoketang/
class TestRandom():
def test_01(self):
print("用例1")
def test_02(self):
print("用例2")
def test_03(self):
print("用例3")
module2/test_order2.py內容
# module2/test_order2.py
# 作者-上海悠悠 QQ交流群:717225969
# blog地址 https://www.cnblogs.com/yoyoketang/
class TestDemo():
def test_04(self):
print("用例4")
def test_05(self):
print("用例5")
def test_06(self):
print("用例6")
帶上--random-order參數運行用例
>pytest --random-order -v
================================================= test session starts =================================================
Using --random-order-bucket=module
Using --random-order-seed=357703
collected 6 items
module2/test_order2.py::TestDemo::test_04 PASSED [ 16%]
module2/test_order2.py::TestDemo::test_05 PASSED [ 33%]
module2/test_order2.py::TestDemo::test_06 PASSED [ 50%]
module1/test_order1.py::TestRandom::test_03 PASSED [ 66%]
module1/test_order1.py::TestRandom::test_02 PASSED [ 83%]
module1/test_order1.py::TestRandom::test_01 PASSED [100%]
================================================== 6 passed in 0.05s ==================================================
從運行的結果可以看出,默認使用--random-order-bucket=module,模塊下的用例會被打亂隨機執行,每次運行會重新生成--random-order-seed=357703,seed值不一樣,用例的順序也會不一樣
--random-order-bucket 隨機范圍
要更改重新排序與范圍,運行pytest --random-order-bucket=
插件組在存儲桶中進行測試,在存儲桶中進行混洗,然后對存儲桶進行混洗,設計原理如圖

給定上面的測試套件,以下是一些可能生成的測試順序中的兩個:

可以從以下幾種類型的存儲桶中進行選擇:
- class 測試將在一個類中進行混洗,而各類將被混洗,但是來自一個類的測試將永遠不會在其他類或模塊之間運行來自其他類的測試。
- module 模塊級別。如果僅使用--random-order運行pytest,同時帶上參數--random-order-seed=
。 - package 程序包級別。請注意,屬於package的模塊(以及這些模塊內的測試)x.y.z不屬於package x.y,因此在對存儲package桶類型進行隨機分配時,它們將落入不同的存儲桶中。
- parent 如果使用的是不屬於任何模塊的自定義測試項,則可以使用此項將測試項的重新排序限制在它們所屬的父級中。對於正常測試函數,父級是聲明它們的模塊。
- grandparent 類似於上面的parent,但是使用測試項的父級作為bucket key。
- global 所有測試屬於同一存儲桶,完全隨機,測試可能需要更長的時間才能運行。
- none (已棄用) 禁用混洗。自1.0.4起不推薦使用,因為此插件默認不再重做測試,因此沒有禁用的功能。
如果你有測試三個桶A,B和C三個測試1和2,並3在他們每個人,那么許多潛在的排序的一個非全局隨機化可以產生可能是:
c2,c1,c3,a3,a1,a2,b3,b2,b1
運行示例,帶上參數--random-order-bucket=global,所有的用例都會被打亂。
>pytest --random-order -v --random-order-bucket=global
================================================= test session starts =================================================
Using --random-order-bucket=global
Using --random-order-seed=255529
collected 6 items
module1/test_order1.py::TestRandom::test_02 PASSED [ 16%]
module1/test_order1.py::TestRandom::test_01 PASSED [ 33%]
module2/test_order2.py::TestDemo::test_06 PASSED [ 50%]
module2/test_order2.py::TestDemo::test_04 PASSED [ 66%]
module2/test_order2.py::TestDemo::test_05 PASSED [ 83%]
module1/test_order1.py::TestRandom::test_03 PASSED [100%]
================================================== 6 passed in 0.05s ==================================================
最好從最小的存儲桶類型開始(class或module取決於您是否有基於類的測試),並在確定測試可以處理較大的存儲桶類型時切換為更大的存儲桶類型。
如果您的測試依賴模塊或會話范圍的fixture,則測試的隨機性越高,測試速度就越慢。您可能不想在編碼時隨機global或隨機分組,package並且需要快速確認沒有什么大問題。``
模塊或類中禁用隨機
如果我們在一個模塊或類中,不想讓里面的用例隨機,可以設置 disabled=True 來禁用隨機參數
# 寫在.py文件最上面即可
pytestmark = pytest.mark.random_order(disabled=True)
def test_number_one():
assert True
def test_number_two():
assert True
也可以寫在class里面
import pytest
# 作者-上海悠悠 QQ交流群:717225969
# blog地址 https://www.cnblogs.com/yoyoketang/
class TestRandom():
pytestmark = pytest.mark.random_order(disabled=True)
def test_01(self):
print("用例1")
def test_02(self):
print("用例2")
def test_03(self):
print("用例3")
這樣在執行的時候,TestRandom里面的用例順序就是test_01,test_02,test_03不會被打亂
--random-order-seed 隨機種子
如果由於重新排序測試而發現測試失敗,則可能希望能夠以相同的失敗順序重新運行測試。為了允許重現測試訂單,該插件報告其與偽隨機數生成器一起使用的種子值:
============================= test session starts ==============================
..
Using --random-order-bucket=module
Using --random-order-seed=24775
...
現在,您可以使用該--random-order-seed=...位作為下一次運行的參數以產生相同的順序:
pytest -v --random-order-seed = 24775
禁用插件
如果你覺得這個插件不好用,或者對你的其它功能會有影響,則可以將其禁用
pytest -p no:random_order
請注意,默認情況下禁用隨機化。通過傳遞,-p no:random_order您將阻止插件的注冊,因此其鈎子將不會被注冊,並且命令行選項也不會出現在中--help
首先運行最后失敗的測試
另外 --failed-first 標志-上一次運行失敗的測試將在通過測試之前運行,而不管改組存儲桶類型如何。
