zoukankan      html  css  js  c++  java
  • python unittest 失败用例重跑最佳实现方法

    本篇博文参考了简书博文,原文链接: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遍

  • 相关阅读:
    我的WCF之旅(7):面向服务架构(SOA)和面向对象编程(OOP)的结合——如何实现Service Contract的继承(转载)
    我的WCF之旅(4):WCF中的序列化(Serialization) Part I(转载)
    我的WCF之旅(1):创建一个简单的WCF程序(转载)
    我的WCF之旅(3):在WCF中实现双向通信(Bidirectional Communication)(转载)
    我的WCF之旅(2):Endpoint Overview(转载)
    C#中Attribute特性的用法(转载)
    我的WCF之旅(5):Service Contract中的重载(Overloading)(转载)
    我的WCF之旅(6):在Winform Application中调用Duplex Service出现TimeoutException的原因和解决方案(转载)
    [转] 81条经典话语~~~当裤子失去皮带,才懂得什麽叫做依赖
    HP大中华区总裁孙振耀退休十五天后九大感言,快毕业或者已经毕业的都来看看,与其浑浑噩噩一辈子,不如花这半小时看看
  • 原文地址:https://www.cnblogs.com/5566yesongqiao/p/14049432.html
Copyright © 2011-2022 走看看