python+unittest实现当case出错或者程序报错时,退出driver,并重新打开driver,并执行下一条case

首先创建case_set.py文件继承 unittest.TestCase 类,

case_set.py

class MyTest(unittest.TestCase):

    # 整个Test类的开始和结束执行

    driver = None

    @classmethod
    def setUpClass(cls):
        print("test class start =======>")
        cls.hp = help()
        cls.driver = cls.hp.run()




    @classmethod
    def tearDownClass(cls):
        print("test class end =======>")
        cls.driver.quit()
        



    def setUp(self):
        pass

    def tearDown(self):
        pass

在MyTest类中实现setUpClass,tearDownClass,用于整个Test类的开始和结束执行,

在setUpClass中实现启动app driver并获得driver,在tearDownClass中实现当一个Test类执行完毕后退出driver,然后后面写的每一个Test类(具体的case)都继承自MyTest。

起初的想法是这样做的,好处很明显,就是不用每次执行case都重启driver,节省了大量的时间。

但是这样做有2个很明显的问题,第一个就是用例的耦合度变高了,case与case之间必须有上下级关联关系

还有一个致命问题:比如登录页面和登录成功后的认证页面,如果上一条登录case执行失败或者程序报错后,会停留在当前的登录页面,继续执行下一条认证的case的时候,因为登录case失败,所以认证的case会因为找不到元素报错。这样就导致一旦某一条case执行失败,那么所有的case都会执行失败

第一个问题好解决,有上下级关联就有关联,因为有的case与case之间也是存在上下级关联的,

第二个问题目前的想法就是,一旦某一条case执行失败或者报错,那么就直接退出driver,重新打开driver,并在执行下一条case的时候设置前置的操作,比如登录页面的case执行失败后,执行下一条认证的case的时候,首先判断是否需要前置操作(其实就是判断app是否重新打开过了,可以通过获取页面元素来判断),如果重开了,就需要就执行前置操作登录操作。这样就完美解决了目前的问题,以后所有的case都写一些前置的操作

那么如何来判断程序是如何出错的呢?怎么获得异常?这里我参考了一下别人的博客内容

https://www.cnblogs.com/ywhyme/p/10657345.html  感谢大神分享,

完整的实现方法如下

import contextlib
import sys
import unittest
from help.db_help import help
from unittest.case import SkipTest, _ShouldStop, _Outcome
from help.is_open_driver import Singleton

@contextlib.contextmanager
def testPartExecutor(self, test_case, isTest=False):
    old_success = self.success
    self.success = True
    try:
        yield
    except Exception:
        try:
            # if error
            getattr(test_case, test_case._testMethodName).__func__._error = True
            raise
        except KeyboardInterrupt:
            raise
        except SkipTest as e:
            self.success = False
            self.skipped.append((test_case, str(e)))
        except _ShouldStop:
            pass
        except:
            exc_info = sys.exc_info()
            if self.expecting_failure:
                self.expectedFailure = exc_info
            else:
                self.success = False
                self.errors.append((test_case, exc_info))
            # explicitly break a reference cycle:
            # exc_info -> frame -> exc_info
            exc_info = None
    else:
        if self.result_supports_subtests and self.success:
            self.errors.append((test_case, None))
    finally:
        self.success = self.success and old_success



_Outcome.testPartExecutor = testPartExecutor

# 整个文件的开始和结束执行
def setUpModule():
    print("test module start >>>>>>>>>>>>>>")
    pass


def tearDownModule():
    print("test module end >>>>>>>>>>>>>>")
    pass



class MyTest(unittest.TestCase):

    # 整个Test类的开始和结束执行

    driver = None

    @classmethod
    def setUpClass(cls):
        print("test class start =======>")
        cls.hp = help()
        cls.driver = cls.hp.run()




    @classmethod
    def tearDownClass(cls):
        print("test class end =======>")
        cls.driver.quit()
        pass



    def setUp(self):
        if(Singleton().is_need_open_driver):
            self.setUpClass()
            Singleton().change_not_need_open_driver()



    def tearDown(self):
        #如果用例执行失败,则退出driver
        if hasattr(getattr(self, self._testMethodName), "_error"):
            # dosomething 可以进行比如打印日志,截图,等等操作
            self.driver.quit()
            Singleton().change_need_open_driver()
            pass

当程序出错或者case失败时,则一定会进入tearDown方法中,这里实现的就是判断是否case执行成功,(ps:查看源码后发现每次case执行失败后会清楚掉erroes,所以不会出现下一个case运行成功时tearDown方法的错误判断)

如果有错误则执行driver的退出操作,并设置标注状态需要重新打开driver,Singleton类是单例模式来实现的,用来保存is_need_open_driver属性的值,

实现逻辑


#单例模式,每次初始化的时候,不改变类中属性的值,沿用同一套属性值
class Singleton(object):
    instance = None
    init_flag = False

    def __new__(cls, *args, **kwargs):
        if cls.instance is None:
            cls.instance = super().__new__(cls)

        return cls.instance

    def __init__(self):
        if Singleton.init_flag:
            return
        Singleton.init_flag = True
        #添加是否需要重新启动driver的判断
        self.is_need_open_driver = False

    #改变是否需要重新启动driver的判断的值
    def change_need_open_driver(self):
        self.is_need_open_driver = True

    def change_not_need_open_driver(self):
        self.is_need_open_driver = False

为什么is_need_open_driver这个属性值不直接写在MyTest类中呢?而是通过单例模式来保存下来?

因为我发现如果直接写在MyTest类中,上一条case执行失败,在执行下一条case的时候,即使在tearDown方法中改变了该属性的值,但是在setUp重新去获取该值时,还是获取的改变前的值,很奇怪,不晓得是什么情况导致的,我感觉也许是在执行下一条case的时候重新初始化了该MyTest类导致的,不晓得是不是这个原因,所以就想到了单例模式。有知道原因的请留言哈。。

最后,最最重要的是在setUp中重新启动driver,千万不要在setUp方法中重新去打开一个driver,否则程序执行会报错,正确的做法是需要重新调用实现setUpClass()方法

因为setUpClass()该方法的实现是整个Test类的执行开始和结束,Test类中的case未全部执行完成时,如果你在setUp方法中重新去打开一个driver,即使你重新赋值driver也不能覆盖原来的driver属性(虽然我也不晓得是个什么原因),那么你这次执行的case其实就是使用的setUp中的driver,但是你的下下条case,使用的却是setUpClass()方法中的driver,此时setUpClass()中的driver因为上个异常case关闭了,一定会报错。

所以这里只能重新调用setUpClass()中的方法,并重新覆盖driver。

最后附上测试后的case截图,如果有知道上面我说的2个原因的,请留言解答下哈

如果大家有更加合适的解决办法,也请留言,我觉得我这样做虽然解决了问题,但是绕了一圈

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我会依次回答你的问题。首先,关于Python+unittest编写测试用例和测试驱动程序的过程,具体步骤如下: 1. 安装Pythonunittest库。 2. 编写测试用例,即编写测试类和测试方法,在测试方法编写测试代码。 3. 编写测试驱动程序,即编写主程序,调用测试用例并运行测试代码。 4. 运行测试驱动程序,查看测试结果。 下面是一个简单的示例: ```python import unittest class TestStringMethods(unittest.TestCase): def test_upper(self): self.assertEqual('foo'.upper(), 'FOO') def test_isupper(self): self.assertTrue('FOO'.isupper()) self.assertFalse('Foo'.isupper()) if __name__ == '__main__': unittest.main() ``` 在上面的示例,我们定义了一个名为TestStringMethods的测试类,其包含两个测试方法test_upper和test_isupper。在测试方法,我们使用了unittest库提供的assertEqual和assertTrue/False方法对测试结果进行判断。最后,我们在主程序调用unittest库提供的main函数,运行测试驱动程序并查看测试结果。 接下来,关于实现嵌入式自动化测试的基本流程,具体步骤如下: 1. 确定测试目标和测试需求。 2. 设计测试用例,包括输入输出、边界条件、异常情况等。 3. 编写测试代码,包括测试类和测试方法。 4. 配置测试环境,包括硬件设备、模拟器、仿真器等。 5. 运行测试代码,收集测试结果。 6. 分析测试结果,对测试代码进行优化和改进。 在实现嵌入式自动化测试,需要注意以下几点: 1. 确保测试代码和被测试的代码在同一环境运行。 2. 选择适当的测试工具和框架,如Python+unittest、Robot Framework等。 3. 编写清晰、简洁、可维护的测试代码。 4. 对测试结果进行统计和分析,及发现和解决问题。 希望以上回答能够帮助到你!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值