python unittest 失敗用例重跑最佳實現方法
阿新 • • 發佈:2020-11-27
本篇博文參考了簡書博文,原文連結:https://www.jianshu.com/p/2c471acfea2e
當我們自動化用例多的時候,經常會有部分用例因為各種各樣的原因跑失敗,但其實應用本身是沒有問題的,所以,加入失敗用例重跑機制,如果第二次執行成功,那麼我們就認為這條用例是通過的,同時,測試報告上面寫的也是通過
這裡介紹兩種方法。一種是函式裝飾器,一種是類裝飾器。兩者功能相同
函式裝飾器
# -*- coding = UTF-8 -*- # Autohr : 葉鬆橋 # File : runfailed.py # project : Test_Ui_Yt # time : 2020/11/27 12:21 # Describe : 失敗用例重跑 # --------------------------------------- import sys import functools import traceback import inspect import unittest def retry(target=None, max_n=1, func_prefix="test"): """ 一個裝飾器,用於unittest執行測試用例出現失敗後,自動重試執行 # example_1: test_001預設重試1次 class ClassA(unittest.TestCase): @retry def test_001(self): raise AttributeError # example_2: max_n=2,test_001重試2次 class ClassB(unittest.TestCase): @retry(max_n=2) def test_001(self): raise AttributeError # example_3: test_001重試3次; test_002重試3次 @retry(max_n=3) class ClassC(unittest.TestCase): def test_001(self): raise AttributeError def test_002(self): raise AttributeError # example_4: test_102重試2次, test_001不參與重試機制 @retry(max_n=2, func_prefix="test_1") class ClassD(unittest.TestCase): def test_001(self): raise AttributeError def test_102(self): raise AttributeError :param target: 被裝飾的物件,可以是class, function :param max_n: 重試次數,沒有包含必須有的第一次執行 :param func_prefix: 當裝飾class時,可以用於標記哪些測試方法會被自動裝飾 :return: wrapped class 或 wrapped function """ def decorator(func_or_cls): if inspect.isfunction(func_or_cls): @functools.wraps(func_or_cls) def wrapper(*args, **kwargs): n = 0 while n <= max_n: try: n += 1 func_or_cls(*args, **kwargs) return except Exception: # 可以修改要捕獲的異常型別 if n <= max_n: trace = sys.exc_info() traceback_info = str() for trace_line in traceback.format_exception(trace[0], trace[1], trace[2], 3): traceback_info += trace_line print(traceback_info) # 輸出組裝的錯誤資訊 args[0].tearDown() args[0].setUp() else: raise return wrapper elif inspect.isclass(func_or_cls): for name, func in list(func_or_cls.__dict__.items()): if inspect.isfunction(func) and name.startswith(func_prefix): setattr(func_or_cls, name, decorator(func)) return func_or_cls else: raise AttributeError if target: return decorator(target) else: return decorator
類裝飾器
# -*- coding = UTF-8 -*- # Autohr : 葉鬆橋 # File : runfailed.py # project : Test_Ui_Yt # time : 2020/11/27 12:21 # Describe : 失敗用例重跑 # --------------------------------------- import sys import functools import traceback import inspect import unittest class Retry(object): """ 類裝飾器, 功能與Retry一樣 # example_1: test_001預設重試1次 class ClassA(unittest.TestCase): @Retry def test_001(self): raise AttributeError # example_2: max_n=2,test_001重試2次 class ClassB(unittest.TestCase): @Retry(max_n=2) def test_001(self): raise AttributeError # example_3: test_001重試3次; test_002重試3次 @Retry(max_n=3) class ClassC(unittest.TestCase): def test_001(self): raise AttributeError def test_002(self): raise AttributeError # example_4: test_102重試2次, test_001不參與重試機制 @Retry(max_n=2, func_prefix="test_1") class ClassD(unittest.TestCase): def test_001(self): raise AttributeError def test_102(self): raise AttributeError """ def __new__(cls, func_or_cls=None, max_n=1, func_prefix="test"): self = object.__new__(cls) if func_or_cls: self.__init__(func_or_cls, max_n, func_prefix) return self(func_or_cls) else: return self def __init__(self, func_or_cls=None, max_n=1, func_prefix="test"): self._prefix = func_prefix self._max_n = max_n def __call__(self, func_or_cls=None): if inspect.isfunction(func_or_cls): @functools.wraps(func_or_cls) def wrapper(*args, **kwargs): n = 0 while n <= self._max_n: try: n += 1 func_or_cls(*args, **kwargs) return except Exception: # 可以修改要捕獲的異常型別 if n <= self._max_n: trace = sys.exc_info() traceback_info = str() for trace_line in traceback.format_exception(trace[0], trace[1], trace[2], 3): traceback_info += trace_line print(traceback_info) # 輸出組裝的錯誤資訊 args[0].tearDown() args[0].setUp() else: raise return wrapper elif inspect.isclass(func_or_cls): for name, func in list(func_or_cls.__dict__.items()): if inspect.isfunction(func) and name.startswith(self._prefix): setattr(func_or_cls, name, self(func)) return func_or_cls else: raise AttributeError
執行效果如圖,失敗的用例會再次執行2遍