pytest失敗重跑插件: pytest-rerunfailures使用與坑(全網獨家精華)


背景

在編寫接口case的時候,我們常遇到一個這樣的問題:

測試環境不穩定偶發接口超時(和服務無關,純粹是環境問題),然后執行接口case也因此偶發失敗。比如同一個接口case跑五次,其中有兩次失敗,另外三次都是成功的,這種偶發性的環境問題就需要我們手動重跑(還不一定能夠通過)。有沒有一個比較好的機制,保證case能夠盡最大努力通過測試呢?

這里我們介紹pytest的一個失敗重跑插件:pytest-rerunfailures

介紹

pytest-rerunfailures是一個通過重跑機制來消除不穩定失敗的pytest插件。

項目地址:https://github.com/pytest-dev/pytest-rerunfailures

安裝

安裝&運行要求:

  • Python 3.6~3.9, or PyPy3
  • pytest 5.0+

安裝插件

sudo pip(pip3) install pytest-rerunfailures

使用pytest-rerunfailures

使用方式有兩種:

  • 命令行參數
  • 裝飾器方式

命令行參數模式

示例case:test_demo.py

#!/usr/bin/env python3
#!coding:utf-8
import pytest
import random

def test_simple_assume():
    #每次case運行的值為1或者2,具有隨機性
    r = random.randint(1,2)
    assert r == 1

如果我們直接運行pytest test_demo.py,那么每次運行的結果會具有一定隨機性(可能成功也可能失敗)

如果使用pytest-rerunfailures指定執行多次,只要執行次數足夠多,那么遇到結果成功的機會就會更多。

例子1

指定失敗重跑最大次數為10:pytest --reruns 10

如下圖,我們看到一共跑了次,第一次結果失敗,所以重跑了第二次,最終結果用R標注。(如果跑一次就成功,結果應該是'.')

例子2

指定失敗重跑最大次數為10,重跑間隔為1秒pytest --reruns 10 --reruns-delay 1

如下圖,一共重跑了兩次,重跑兩次的執行時間為2.1秒,上圖中一次只需要0.07秒,這里多出的兩秒就是因為--reruns-delay指定的重跑間隔為1秒。

例子3:通過表達式指定失敗重跑

test_demo.py解釋:

  • test_assert_error隨機拋出AssertionError

  • test_value_error隨機拋出ValueError

#!/usr/bin/env python3
#!coding:utf-8
import pytest
import random

def test_assert_error():
    r = random.randint(1,2)
    with pytest.raises(AssertionError):
        #這里如果不使用pytest.raises顯式拋出AssertionError異常,pytest-rerunfailures無法捕獲到assert r == 1,應該是該插件的bug。
        assert r == 1

def test_value_error():
    r = random.randint(1,2)
    if r == 1:
        s = int('www')

執行:pytest --reruns 10 --only-rerun AssertionError --only-rerun ValueError test_demo.py -v

其中多個--only-rerun之間是或的關系

如上圖,遇到AssertionErrorValueError的情況下都被重跑了

裝飾器模式

test_demo.py 

  • test_assert_error隨機拋出AssertionError,最多失敗重跑五次

  • test_value_error隨機拋出ValueError,最多失敗重跑五次,失敗重跑間隔為2秒

  • test_value_error_condition,最多失敗重跑五次,僅當系統為win32系統才重跑。

#!/usr/bin/env python3
#!coding:utf-8
import pytest
import random
import sys

#這個最多失敗重跑五次 @pytest.mark.flaky(reruns
=5) def test_assert_error(): r = random.randint(1,2) #raise AssertionError("ERR") with pytest.raises(AssertionError): assert r == 1
#這個最多失敗重跑五次 
@pytest.mark.flaky(reruns=5, reruns_delay=2) 
def test_value_error():
  r
= random.randint(1,2)
  if r == 1:
    s
= int('nick')
#官網的這個例子有問題,如果拿mac或者linux機器跑也會有重試(condition中指定的是win32平台才會觸發重跑機制)
@pytest.mark.flaky(reruns=5, condition=not sys.platform.startswith("win32")) 
def test_value_error_condition():
  r
= random.randint(1,2)
    if r == 1:
      s
= int('nick')

執行:pytest -v 

這里前面兩個testcase都有過失敗重跑,但是第三個也重跑了(作者原意是condition為False情況下不會重跑),這里是有bug的,即condition是無效的

去查看項目源碼,果然發現這里有些問題,是否不重跑的函數里面用的是or,即最后一個not condition只是不重跑的條件之一,如果前面滿足重跑,則condition這個參數可以被忽略掉。

兼容性

  • 不可以與類,模塊還有包級別的fixture裝飾器一起使用: @pytest.fixture() 
  • 該插件與pytest-xdist的 --looponfail 標志不兼容
  • 該插件在使用pdb調試時候會有不兼容性

最后總結,這個插件雖然還用,但是坑還是不少,建議主要使用失敗重試次數和重試間隔的功能即可。 

博主:測試生財(一個不為996而996的測開碼農)

座右銘:專注測試開發與自動化運維,努力讀書思考寫作,為內卷的人生奠定財務自由。

內容范疇:技術提升,職場雜談,事業發展,閱讀寫作,投資理財,健康人生。

csdn:https://blog.csdn.net/ccgshigao

博客園:https://www.cnblogs.com/qa-freeroad/

51cto:https://blog.51cto.com/14900374

微信公眾號:測試生財(定期分享獨家內容和資源)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM