python基础之类与对象的应用-单元测试unittest模块

单元测试的本质

测试函数,从代码级别上进行测试

单元测试的框架

python+unittest

unittest模块

  • python自带不需安装

  • 结构

    • 写用例 Testcase --- 方法
    • 执行用例
      • 1.TestSuite 存储用例 --- 类
      • 2.TestLoader 找用例,加载用例,存到1中的TestSuite --- 类
    • 对比实际结果 断言 Assert
    • 出具测试报告 TextTestRunner
  • 测试自己的类

    python基础之初识类与对象 超继承示例中的MathMethod类

    #测试MathMethod类
    
    from py_0909.super import MathMethod #导入待测的类
    import unittest
    
    class TestMathMethod(unittest.TestCase):#继承与unittest的Testcase方法
    
        #编写测试用例
        def test_add_two_positive(self): #测试两个正数相加
            res=MathMethod(1,1).add() #实例化调用待测的方法
            print("1+1的结果是:",res)
    
        def test_add_two_zero(self): #测试两个0相加
            res = MathMethod(0, 0).add()
            print("0+0的结果是:", res)
    
        def test_add_two_negative(self): #测试两个负数相加
            res = MathMethod(-1, -1).add()
            print("-1+(-1)的结果是:", res)
    
    if __name__ == '__main__':
        unittest.main() #unitest.main()函数用来测试类中以test开头的测试用例
    

    运行测试用例的结果:


    image
  • 说明

    • 一个用例是一个函数,不能传参,只有self关键字

    • 所有的用例都是test开头,test_,例如test_add_two_positive

    • Testcase默认的执行顺序是按函数名的ASCII码

配置测试用例的执行顺序

  • 如果想测试用例不按默认的执行顺序,可以通过TestSuite类、TestLoader类搭配使用配置测试用例执行顺序

  • TestSuite类说明(command键+鼠标左键进入)

    • TestSuite测试套件是由测试用例组成的复合测试。

    • 要使用,请创建testsuite的实例,然后添加测试用例实例。使用suite.add('方法名')添加测试用例

    • 添加完测试用例后,将TestSuite传递给TextTestRunner

    • 它将按添加顺序运行各个测试用例

  • 执行少量用例时,配置测试用例顺序

    #新建一个py文件
    import unittest
    from py_inter0913.unittest_01 import TestMathMethod #导入写了测试用例的类
    
    #创建TestSuite实例,存储测试用例
    suite=unittest.TestSuite() 
    
    #构造测试套件
    suite.addTest(TestMathMethod('test_add_two_positive')) #添加测试用例,必须传入参数--函数名
    suite.addTest(TestMathMethod('test_add_two_zero'))
    suite.addTest(TestMathMethod('test_add_two_negative'))
    
    #执行用例
    runner=unittest.TextTestRunner() 
    runner.run(suite)
    

    运行结果: 按我们添加测试用例的顺序执行


    image
  • 执行大量用例的方法,使用TestLoader

    import unittest
    from py_inter0913.unittest_01 import TestMathMethod #导入写了测试用例的类
    #创建一个加载器
    suite=unittest.TestSuite() #创建TestSuite实例,存储测试用例
    loader=unittest.TestLoader()
    suite.addTest(loader.loadTestsFromTestCase(TestMathMethod))
    # 从测试类里去找 import也需要导到模块处 搭配loadTestsFromModule使用
    # from py_inter0913 import unittest_01
    # suite.addTest(loader.loadTestsFromModule(unittest_01))
    
    #执行用例
    runner=unittest.TextTestRunner()
    runner.run(suite)
    
  • setUp()和tearDown()

    在测试类中添加setUp()、tearDown()方法,会在单条测试用执行开始前和结束后执行。

    • setUp()、tearDown()是TestCase里的方法,写在测试类中,就是方法的重写。
    class TestMathMethod(unittest.TestCase):
    def setUp(self):
        print("准备开始执行测试用例了")
        
    def tearDown(self):
        print("结束了")
        
    #编写测试用例
    def test_add_two_positive(self): #测试两个正数相加
        res=MathMethod(1,1).add()
        print("1+1的结果是:",res)
    
    • 执行顺序是:
      setUp->testA->tearDown->setUp->testB>tearDown

断言

断言就是预期结果。如果不加断言,没有结果对比,需要手动去检查运行的结果是否符合预期。

  • assertEqual()

    def assertEqual(self, first, second, msg=None):
        """Fail if the two objects are unequal as determined by the '=='
           operator.
        """
    
    • first 预期结果
    • second 实际结果
    • msg 出错时,输出的错误信息,可不填
  • 断言使用

    在测试用例中写入断言

    from py_0909.super import MathMethod #导入待测的类
    import unittest
    
    #测试MathMethod类
    class TestMathMethod(unittest.TestCase):
        #编写测试用例
        def test_add_two_positive(self): #测试两个正数相加
            res=MathMethod(1,1).add()
            print("1+1的结果是:",res)
            self.assertEqual(2,res,"两个正数相加出错了") #断言
    
        def test_add_two_zero(self): #测试两个0相加
            res = MathMethod(0, 0).add()
            print("0+0的结果是:", res)
            self.assertEqual(0, res, "两个0相加出错了") #断言
    
        def test_add_two_negative(self): #测试两个负数相加
            res = MathMethod(-1, -1).add()
            print("-1+(-1)的结果是:", res)
            self.assertEqual(-2, res, "两个负数相加出错了") #断言
    
    if __name__ == '__main__':
        unittest.main()
    
  • 其他断言语法


    image
  • 断言的异常处理

    from py_0909.super import MathMethod #导入待测的类
    import unittest
    
    #测试MathMethod类
    class TestMathMethod(unittest.TestCase):
        #编写测试用例
        def test_add_two_positive(self): #测试两个正数相加
            res=MathMethod(1,1).add()
            print("1+1的结果是:",res)
            try: #断言的异常处理
                self.assertEqual(0,res,"两个正数相加出错了") #断言
            except AssertionError as e:
                print("断言出错,错误是:{0}".format(e)) #对异常的处理:输出错误语句、存储到excel等
                raise e #异常处理完要抛出去,否则输出结果中不会报错
    
        def test_add_two_zero(self): #测试两个0相加
            res = MathMethod(0, 0).add()
            print("0+0的结果是:", res)
            try:
                self.assertEqual(1, res, "两个0相加出错了") #断言
            except AssertionError as e:
                print("断言出错,错误是:{0}".format(e))
                raise e
    
        def test_add_two_negative(self): #测试两个负数相加
            res = MathMethod(-1, -1).add()
            print("-1+(-1)的结果是:", res)
            try:
                self.assertEqual(-1, res, "两个负数相加出错了") #断言
            except AssertionError as e:
                print("断言出错,错误是:{0}".format(e))
                raise e
    
    if __name__ == '__main__':
        unittest.main()
    
    • 从错误的输出可以知道,异常的基类是AssertionError。
    • 捕获异常,要对异常进行处理,处理之后,要将异常抛出,否则在结果报告中,不会报错。raise e

测试报告

  • TextTestRunner


    image

    TextTestRunner是一个以文本形式展示测试结果的测试运行程序类

    • stream 输出报告的路径,默认输出控制台
    • verbosity 控制输出报告的详细程度,从0-2,越来越详细
    import unittest
    from py_inter0913.unittest_01 import TestMathMethod #导入写了测试用例的类
    suite=unittest.TestSuite() #创建TestSuite实例,存储测试用例
    loader=unittest.TestLoader()
    suite.addTest(loader.loadTestsFromTestCase(TestMathMethod))
    
    #执行用例
    with open("result.txt","w+") as file:
        runner=unittest.TextTestRunner(stream=file,verbosity=2)
        runner.run(suite)
    
  • HTMLTestRunner

    使用unittest自带的报告不够美观。HTMLTestRunner是Python标准库的unittest模块的扩展。它生成易于使用的HTML测试报告。

    import HTMLTestRunner
    import unittest
    from py_inter0913.unittest_01 import TestMathMethod #导入写了测试用例的类
    suite=unittest.TestSuite() #创建TestSuite实例,存储测试用例
    loader=unittest.TestLoader()
    suite.addTest(loader.loadTestsFromTestCase(TestMathMethod))
    
    with open("result.html","wb") as file:
        runner=HTMLTestRunner.HTMLTestRunner(stream=file, title="MathMethod测试", verbosity=2,)
        runner.run(suite)
    
    

    运行之后会发现报错:No module named 'StringIO',原因是自己使用python3,而下载的HTMLTestRunner适用于Python2.X,需要自己对模块进行修改。

    参考文档:https://www.bbsmax.com/A/QW5YL9jeJm/

    • html格式的报告:
    image

    实战中问题

    • SSLError:http://2.python-requests.org/zh_CN/latest/user/advanced.html#ssl

      方法1.在参数中加入verify=False可以不进行安全验证,requests.get('https://github.com', verify=True)

      方法2.为 verify 传入 CA_BUNDLE 文件的路径,或者包含可信任 CA 证书文件的文件夹路径。requests.get('https://github.com', verify='/path/to/certfile')

- 作业思路
    - 测试用例.py
        - 实例化调用被测类的方法进行测试用例编写
        - 断言
        - 异常处理
    - 测试套件.py
        - 存储要运行的测试用例
        - 执行测试套件中的测试用例
        - 根据测试套件.py中生成测试报告
        
- cookie处理

    - 相当于面试题:后面的用例需要用到前面返回的某些值如何解决?

    - 方法1:setUp()方法
    
        大部分请求都要带着cookie,可以写一个登录的用例到`def setUp()`中,每一条用例都采用登录的cookie
        ```
        def setUp():
            response=request.get(url,data)
            cookie=response.request.cookie
            
        def add(self,url,data,cookie):
            ...
            
        ```
    - 方法2:全局变量 
        ```
        COOKIE=None #全局变量

        class TestHttp(unittest.Testcase):
            def add(self):
                golbal COOKIE #声明全局变量
                response=request.get(url,data)
                if response.cookies: #如果response.cookies有值
                    COOKIE=response.cookies #给全局变量赋新值
        ```
        缺点是关联性太强,比如登录失败,其他都跪了
    
    - 方法3:反射机制 setattr\hasattr\getattr\delattr
    
        `setattr(类名,"属性名","属性值")`
        
        ```
        # 示例
        class GetData:
            Cookie="小郭"

        if __name__ == '__main__':
            print(GetData.Cookie)
            setattr(GetData,"Cookie","小黄")#set类中的属性值进行修改,attr--attribute
            print(GetData.Cookie)
            print(hasattr(GetData,"Cookie"))#判断是否有这个属性
            print(getattr(GetData,"Cookie"))#获取这个属性的值
            delattr(GetData,"Cookie") #删除这个属性
            print(hasattr(GetData,"Cookie"))
        ```
        
        实战应用:
        ```
        #get_data.py文件
        class GetData:
            Cookie=None
        ```
        
        ```
        #测试用例.py
        from xxx import get_data
        class TestHttp(unittest.Testcase):
            def add(self):
                golbal COOKIE #声明全局变量
                response=request.get(url,data,getattr(GetData,"Cookie"))
                
        ```

unittest总结

  • unittest原理


    image
  • unittest核心步骤

    • testcase 一个testcase的示例就是一条测试用例
- testsuite 多个测试用例组成一个suite

    - 方法一:suite.addTest("测试用例的函数名")
    - 方法二:TestLoader
        ```
        loader=unittest.TestLoader()
        #该测试类中以test_开头的用例都加载进来
        suite.addTest(loader.loadTestFromTestCase(测试用例的类名))
        #该模块中以test_开头的用例都加载进来,一个模块可能有多个测试类,需要import该模块
        suite.addTest(loader.loadTestFromModule(模块名))
        ```

- testrunner 执行用例
```
runner=unittest.TextTestRunner()
runner.run(suite)
```

- test fixture
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容